package service_test

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/pingcap/agent-git-service/internal/db"
	"github.com/pingcap/agent-git-service/internal/service"
)

func TestGitHubImportAccessCreatesHandoffsWithoutGrantingPermissions(t *testing.T) {
	svc, ctx, cleanup := setupImportTestService(t)
	defer cleanup()

	initiator := db.User{Login: "import-admin", Name: "Import Admin", Type: db.TypeUser, UserKind: db.UserKindHuman, Status: db.UserStatusActive, SiteAdmin: true}
	org := db.User{Login: "target-org", Name: "Target Org", Type: db.TypeOrganization, UserKind: db.UserKindHuman, Status: db.UserStatusActive}
	member := db.User{Login: "ags-alice", Name: "Alice", Type: db.TypeUser, UserKind: db.UserKindHuman, Status: db.UserStatusActive}
	for _, user := range []*db.User{&initiator, &org, &member} {
		if err := svc.DBForCtx(ctx).Create(user).Error; err != nil {
			t.Fatalf("create user %q: %v", user.Login, err)
		}
	}
	mustAddOrgMember(t, svc, ctx, org.ID, member.ID, db.OrganizationRoleMember)
	if err := svc.DBForCtx(ctx).Create(&db.UserIdentity{UserID: member.ID, Provider: "github", Subject: "101"}).Error; err != nil {
		t.Fatalf("create verified source identity: %v", err)
	}
	target := db.Repository{Name: "repo", FullName: "target-org/repo", OwnerID: org.ID, DefaultBranch: "main"}
	if err := svc.DBForCtx(ctx).Create(&target).Error; err != nil {
		t.Fatalf("create target repository: %v", err)
	}
	git, err := svc.GitForCtx(ctx)
	if err != nil {
		t.Fatalf("get git store: %v", err)
	}
	if err := git.Init(ctx, target.FullName, target.DefaultBranch, false); err != nil {
		t.Fatalf("initialize target repository: %v", err)
	}

	source := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		switch r.URL.Path {
		case "/repos/source/repo":
			_, _ = w.Write([]byte(`{"id":1,"node_id":"R1","full_name":"source/repo","html_url":"https://github.com/source/repo","default_branch":"main"}`))
		case "/repos/source/repo/collaborators":
			_, _ = w.Write([]byte(`[{"id":101,"node_id":"U101","login":"source-alice","html_url":"https://github.com/source-alice","permissions":{"pull":true,"push":true}}]`))
		case "/repos/source/repo/teams":
			_, _ = w.Write([]byte(`[{"id":201,"node_id":"T201","name":"Maintainers","slug":"maintainers","html_url":"https://github.com/orgs/source/teams/maintainers","permission":"admin"}]`))
		case "/orgs/source/teams/maintainers/members":
			_, _ = w.Write([]byte(`[{"id":101,"node_id":"U101","login":"source-alice","html_url":"https://github.com/source-alice"}]`))
		default:
			_, _ = w.Write([]byte(`[]`))
		}
	}))
	defer source.Close()

	initiatorCtx := testContextWithUser(ctx, initiator)
	job, err := svc.CreateGitHubImportJob(initiatorCtx, service.CreateGitHubImportInput{
		SourceOwner: "source", SourceRepo: "repo", SourceAPIURL: source.URL,
		TargetOwner: "target-org", TargetRepo: "repo", TargetMode: service.ImportTargetModeExistingEmpty, InitiatorID: initiator.ID,
		Options: service.GitHubImportOptions{ImportCollaborators: true, ImportTeams: true},
	})
	if err != nil {
		t.Fatalf("create import job: %v", err)
	}
	if err := svc.RunGitHubImportJob(initiatorCtx, job.ID, service.GitHubImportRuntimeOptions{SourceToken: "test-token"}); err != nil {
		t.Fatalf("run import job: %v", err)
	}

	var collaboratorCount, teamCount, teamMemberCount, teamRepositoryCount int64
	if err := svc.DBForCtx(ctx).Model(&db.Collaborator{}).Where("repository_id = ?", target.ID).Count(&collaboratorCount).Error; err != nil {
		t.Fatalf("count collaborators: %v", err)
	}
	if err := svc.DBForCtx(ctx).Model(&db.Team{}).Count(&teamCount).Error; err != nil {
		t.Fatalf("count teams: %v", err)
	}
	if err := svc.DBForCtx(ctx).Model(&db.TeamMember{}).Count(&teamMemberCount).Error; err != nil {
		t.Fatalf("count team members: %v", err)
	}
	if err := svc.DBForCtx(ctx).Model(&db.TeamRepository{}).Count(&teamRepositoryCount).Error; err != nil {
		t.Fatalf("count team repositories: %v", err)
	}
	if collaboratorCount != 0 || teamCount != 0 || teamMemberCount != 0 || teamRepositoryCount != 0 {
		t.Fatalf("source access was granted automatically: collaborators=%d teams=%d members=%d team_repositories=%d", collaboratorCount, teamCount, teamMemberCount, teamRepositoryCount)
	}

	var handoffCount int64
	if err := svc.DBForCtx(ctx).Model(&db.ImportItemMapping{}).Where("import_job_id = ? AND target_type = ?", job.ID, "access_handoff").Count(&handoffCount).Error; err != nil {
		t.Fatalf("count access handoffs: %v", err)
	}
	if handoffCount != 3 {
		t.Fatalf("access handoff count = %d, want 3", handoffCount)
	}
}
