//go:build integration

package migration_test

import (
	"context"
	"testing"

	"github.com/google/uuid"

	"github.com/ultisuite/ulti-backend/internal/integrationtest"
	"github.com/ultisuite/ulti-backend/internal/users"
)

func TestMigrationRosterImportAndClaim(t *testing.T) {
	h := integrationtest.RequireHarness(t)
	ctx := context.Background()

	adminClient, adminClaims := integrationtest.RequireAdminClient(t, h)
	if _, err := users.EnsureUser(ctx, h.Pool, adminClaims); err != nil {
		t.Fatalf("ensure admin: %v", err)
	}
	if err := users.GrantPlatformAdmin(ctx, h.Pool, adminClaims.Sub); err != nil {
		t.Fatalf("grant admin: %v", err)
	}

	createResp, err := adminClient.Post("/api/v1/admin/migration/projects", map[string]any{
		"name":            "Roster migration",
		"source_provider": "google",
	})
	integrationtest.FailIf(err, t, "create project")
	integrationtest.FailUnlessStatus(t, createResp, 201)

	var created struct {
		ID string `json:"id"`
	}
	integrationtest.DecodeJSON(t, createResp, &created)

	actResp, err := adminClient.Post("/api/v1/admin/migration/projects/"+created.ID+"/activate", nil)
	integrationtest.FailIf(err, t, "activate project")
	integrationtest.FailUnlessStatus(t, actResp, 200)

	csv := "email,display_name,alternate_emails\n" +
		"migratee-" + uuid.NewString() + "@example.com,Test User,alt-" + uuid.NewString() + "@example.com\n"

	importResp, err := adminClient.Post("/api/v1/admin/migration/projects/"+created.ID+"/roster", map[string]string{
		"csv": csv,
	})
	integrationtest.FailIf(err, t, "import roster")
	integrationtest.FailUnlessStatus(t, importResp, 200)

	var importResult struct {
		Created           int `json:"created"`
		SkippedDuplicates int `json:"skipped_duplicates"`
	}
	integrationtest.DecodeJSON(t, importResp, &importResult)
	if importResult.Created != 1 {
		t.Fatalf("expected 1 created, got %#v", importResult)
	}

	listResp, err := adminClient.Get("/api/v1/admin/migration/projects/" + created.ID + "/roster")
	integrationtest.FailIf(err, t, "list roster")
	integrationtest.FailUnlessStatus(t, listResp, 200)

	var rosterList struct {
		Roster []struct {
			Email       string `json:"email"`
			DisplayName string `json:"display_name"`
			Status      string `json:"status"`
		} `json:"roster"`
	}
	integrationtest.DecodeJSON(t, listResp, &rosterList)
	if len(rosterList.Roster) != 1 {
		t.Fatalf("expected 1 roster entry, got %d", len(rosterList.Roster))
	}
	if rosterList.Roster[0].Status != "invited" {
		t.Fatalf("expected invited status, got %q", rosterList.Roster[0].Status)
	}
	migrateeEmail := rosterList.Roster[0].Email

	dupResp, err := adminClient.Post("/api/v1/admin/migration/projects/"+created.ID+"/roster", map[string]string{
		"csv": csv,
	})
	integrationtest.FailIf(err, t, "duplicate import")
	integrationtest.FailUnlessStatus(t, dupResp, 200)

	var dupResult struct {
		SkippedDuplicates int `json:"skipped_duplicates"`
	}
	integrationtest.DecodeJSON(t, dupResp, &dupResult)
	if dupResult.SkippedDuplicates != 1 {
		t.Fatalf("expected 1 skipped duplicate, got %d", dupResult.SkippedDuplicates)
	}

	var inviteToken string
	err = h.Pool.QueryRow(ctx, `
		SELECT token FROM migration_invites WHERE project_id = $1::uuid AND email = $2
	`, created.ID, migrateeEmail).Scan(&inviteToken)
	if err != nil {
		t.Fatalf("lookup invite token: %v", err)
	}
	if inviteToken == "" {
		t.Fatal("missing invite token for roster entry")
	}

	migrateeClaims := integrationtest.RegularUser(integrationtest.NewExternalID("roster-migratee"))
	migrateeClaims.Email = migrateeEmail
	migrateeClient, err := h.Client(migrateeClaims)
	integrationtest.FailIf(err, t, "migratee client")

	if _, err := users.EnsureUser(ctx, h.Pool, migrateeClaims); err != nil {
		t.Fatalf("ensure migratee: %v", err)
	}

	claimResp, err := migrateeClient.Post("/api/v1/migration/claim", map[string]string{
		"token":        inviteToken,
		"password":     "test-password-123",
		"display_name": "Test User",
	})
	integrationtest.FailIf(err, t, "claim invite")
	integrationtest.FailUnlessStatus(t, claimResp, 200)

	var rosterStatus string
	err = h.Pool.QueryRow(ctx, `
		SELECT status FROM migration_roster WHERE project_id = $1::uuid AND email = $2
	`, created.ID, migrateeEmail).Scan(&rosterStatus)
	if err != nil {
		t.Fatalf("roster status: %v", err)
	}
	if rosterStatus != "claimed" {
		t.Fatalf("expected claimed roster, got %q", rosterStatus)
	}
}
