package im

import (
	"context"
	"os"
	"testing"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/coredb/testkit"
)

var imTiDB testkit.TiDBCoreDBFixture

func TestMain(m *testing.M) {
	os.Exit(testkit.RunTestsWithTiDBCoreDBFixture(m, "im", &imTiDB))
}

func startIMTestPool(t *testing.T, ctx context.Context) coredb.DB {
	t.Helper()
	return imTiDB.RollbackDB(t, ctx)
}

func insertIMWorkspaceMember(t *testing.T, ctx context.Context, db coredb.DB, workspaceID string, memberID string) {
	t.Helper()
	now := time.Now().UTC().Truncate(time.Second)
	userID := "usr_" + workspaceID + "_" + memberID
	orgID := "org_" + workspaceID
	_, err := db.Exec(ctx, `
INSERT INTO users (id, email, name, display_name, password_hash, email_verified_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, 'test-hash', $5, $5, $5)
`, userID, userID+"@example.com", userID, "IM Test User", now)
	if err != nil {
		t.Fatalf("insert user: %v", err)
	}
	_, err = db.Exec(ctx, `
INSERT INTO organizations (id, slug, name, created_by_user_id, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $5)
`, orgID, orgID, "IM Test Org", userID, now)
	if err != nil {
		t.Fatalf("insert organization: %v", err)
	}
	_, err = db.Exec(ctx, `
INSERT INTO workspaces (id, organization_id, slug, name, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $5)
`, workspaceID, orgID, workspaceID, "IM Test Workspace", now)
	if err != nil {
		t.Fatalf("insert workspace: %v", err)
	}
	_, err = db.Exec(ctx, `
INSERT INTO members (id, workspace_id, type, display_name, user_id, workspace_role, status, created_at, updated_at)
VALUES ($1, $2, 'human', 'IM Test Member', $3, 'owner', 'active', $4, $4)
`, memberID, workspaceID, userID, now)
	if err != nil {
		t.Fatalf("insert member: %v", err)
	}
}

func insertIMMember(t *testing.T, ctx context.Context, db coredb.DB, workspaceID string, memberID string) {
	t.Helper()
	now := time.Now().UTC().Truncate(time.Second)
	userID := "usr_" + workspaceID + "_" + memberID
	_, err := db.Exec(ctx, `
INSERT INTO users (id, email, name, display_name, password_hash, email_verified_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, 'test-hash', $5, $5, $5)
`, userID, userID+"@example.com", userID, "IM Test User", now)
	if err != nil {
		t.Fatalf("insert user: %v", err)
	}
	_, err = db.Exec(ctx, `
INSERT INTO members (id, workspace_id, type, display_name, user_id, workspace_role, status, created_at, updated_at)
VALUES ($1, $2, 'human', 'IM Test Member', $3, 'member', 'active', $4, $4)
`, memberID, workspaceID, userID, now)
	if err != nil {
		t.Fatalf("insert member: %v", err)
	}
}

func insertIMScope(t *testing.T, ctx context.Context, db coredb.DB, workspaceID string, scopeID string, scopeType string, createdByMemberID string, latestSeq int64) {
	t.Helper()
	now := time.Now().UTC().Truncate(time.Second)
	_, err := db.Exec(ctx, `
INSERT INTO scopes (
  id, workspace_id, type, identity_key, latest_seq, latest_global_seq,
  latest_message_at, visible_message_count, visible_last_message_at,
  status, created_by_member_id, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5, $5, $6, $5, $6, 'active', $7, $6, $6)
`, scopeID, workspaceID, scopeType, scopeType+":"+scopeID, latestSeq, now, createdByMemberID)
	if err != nil {
		t.Fatalf("insert scope: %v", err)
	}
}

func insertIMScopeMembership(t *testing.T, ctx context.Context, db coredb.DB, scopeID string, memberID string, lastReadSeq int64, removedAt *time.Time) {
	t.Helper()
	now := time.Now().UTC().Truncate(time.Second)
	_, err := db.Exec(ctx, `
INSERT INTO scope_memberships (
  scope_id, member_id, visibility, last_read_seq, last_read_global_seq,
  effective_from_seq, effective_to_seq, created_at, updated_at, removed_at
) VALUES ($1, $2, 'public', $3, $3, 0, NULL, $4, $4, $5)
`, scopeID, memberID, lastReadSeq, now, removedAt)
	if err != nil {
		t.Fatalf("insert scope membership: %v", err)
	}
}

func insertIMTask(t *testing.T, ctx context.Context, db coredb.DB, workspaceID string, scopeID string, memberID string) {
	t.Helper()
	now := time.Now().UTC().Truncate(time.Second)
	channelID := "chn_" + scopeID
	boardID := "brd_" + scopeID
	insertIMScope(t, ctx, db, workspaceID, channelID, "channel", memberID, 0)
	_, err := db.Exec(ctx, `
INSERT INTO task_boards (
  channel_id, workspace_id, next_task_number, created_at, updated_at,
  id
) VALUES ($1, $2, 2, $3, $3, $4)
`, channelID, workspaceID, now, boardID)
	if err != nil {
		t.Fatalf("insert task board: %v", err)
	}
	_, err = db.Exec(ctx, `
INSERT INTO tasks (
  id, task_scope_id, board_id, channel_id, task_number, title, status,
  created_by_member_id, created_by_ref, created_at, updated_at
) VALUES ($1, $2, $3, $4, 1, 'IM Test Task', 'in_progress', $5, $5, $6, $6)
`, "task_"+scopeID, scopeID, boardID, channelID, memberID, now)
	if err != nil {
		t.Fatalf("insert task: %v", err)
	}
}

func insertIMScopeNotification(t *testing.T, ctx context.Context, db coredb.DB, scopeID string, memberID string) {
	t.Helper()
	_, err := db.Exec(ctx, `
INSERT INTO scope_notification_settings (
  scope_id, member_id, state, created_at, updated_at
) VALUES ($1, $2, 'active', NOW(), NOW())
`, scopeID, memberID)
	if err != nil {
		t.Fatalf("insert scope notification: %v", err)
	}
}
