package kb

import (
	"context"

	"github.com/tidbcloud/AgentTeam/internal/agsbridge/wiki"
	"github.com/tidbcloud/AgentTeam/internal/service/memory"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
)

const codeWikiGeneratedLabel = "code-wiki-generated"

type fakeWorkspaceGovernanceAuthorizer struct {
	authorize func(context.Context, string, string) (bool, error)
}

func (a fakeWorkspaceGovernanceAuthorizer) CanAdministerWorkspace(ctx context.Context, workspaceID, principalID string) (bool, error) {
	if a.authorize == nil {
		return false, nil
	}
	return a.authorize(ctx, workspaceID, principalID)
}

type fakeAgentOwnershipSource struct {
	agents []memory.AgentOwnership
	err    error
}

func (s fakeAgentOwnershipSource) ListOwnedAgents(context.Context, string, string) ([]memory.AgentOwnership, error) {
	if s.err != nil {
		return nil, s.err
	}
	return s.agents, nil
}

type fakeAGSRepositoryStore struct {
	ensureRequests []repos.AGSRepositoryEnsureRequest
	repository     repos.RepositoryIdentity
	ensureErr      error
	ensureErrAfter int
	// ensureGrantErr simulates a post-create grant failure: the repo is
	// "created" (appended to ensureRequests) but the grant step fails,
	// mirroring the AGSHTTPRepositoryStore production path where
	// createRepo succeeds but grantSourceRepositoryAccess fails.
	ensureGrantErr error
	grants         []repos.ResourceRepositoryCollaboratorGrant
	grantErr       error
	revokes        []repos.ResourceRepositoryCollaboratorRevoke
	revokeErr      error
	deletes        []repos.RepositoryIdentity
	deleteErr      error
	prunes         []wiki.KBWikiPrune
	writes         []wiki.KBWikiPageWrite
	reconciled     bool
	memoryInits    []memory.MemoryRepositoryInitializeRequest
	memoryInitErr  error
	memoryForks    []memory.MemoryRepositoryForkRequest
	memoryForkErr  error
	snapshotSHA    string
	snapshotErr    error
}

func (s *fakeAGSRepositoryStore) RepositoryExists(_ context.Context, _ repos.RepositoryIdentity) (bool, error) {
	return false, nil
}

func (s *fakeAGSRepositoryStore) ResolveRepositorySnapshot(_ context.Context, _ repos.RepositoryIdentity) (string, error) {
	if s.snapshotErr != nil {
		return "", s.snapshotErr
	}
	if s.snapshotSHA != "" {
		return s.snapshotSHA, nil
	}
	return "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil
}

func (s *fakeAGSRepositoryStore) EnsureRepository(_ context.Context, request repos.AGSRepositoryEnsureRequest) (repos.RepositoryIdentity, error) {
	s.ensureRequests = append(s.ensureRequests, request)
	if s.ensureErr != nil && (s.ensureErrAfter <= 0 || len(s.ensureRequests) > s.ensureErrAfter) {
		return repos.RepositoryIdentity{}, s.ensureErr
	}
	if s.repository.FullName != "" || s.repository.Owner != "" || s.repository.Name != "" || s.repository.ID != "" {
		return s.repository, nil
	}
	repository := repos.RepositoryIdentity{Owner: request.Owner, Name: request.Name, FullName: request.Owner + "/" + request.Name, DefaultBranch: request.DefaultBranch}
	if repository.ID == "" {
		repository.ID = "repo-" + request.RepoRole
	}
	// Simulate the production path: createRepo succeeds but the post-create
	// grant fails. Return the resolved identity alongside the error so the
	// caller can include it in the repos slice for cleanup.
	if s.ensureGrantErr != nil {
		return repository, s.ensureGrantErr
	}
	return repository, nil
}

func (s *fakeAGSRepositoryStore) GrantRepositoryCollaborator(_ context.Context, grant repos.ResourceRepositoryCollaboratorGrant) (repos.ResourceRepositoryCollaboratorGrantResult, error) {
	s.grants = append(s.grants, grant)
	if s.grantErr != nil {
		return repos.ResourceRepositoryCollaboratorGrantResult{}, s.grantErr
	}
	return repos.ResourceRepositoryCollaboratorGrantResult{Materialized: true}, nil
}

func (s *fakeAGSRepositoryStore) RevokeRepositoryCollaborator(_ context.Context, revoke repos.ResourceRepositoryCollaboratorRevoke) error {
	s.revokes = append(s.revokes, revoke)
	return s.revokeErr
}

func (s *fakeAGSRepositoryStore) DeleteRepository(_ context.Context, repository repos.RepositoryIdentity) error {
	s.deletes = append(s.deletes, sourceRepositoryIdentity(repository))
	return s.deleteErr
}

func (s *fakeAGSRepositoryStore) PutPage(_ context.Context, request wiki.KBWikiPageWrite) error {
	s.writes = append(s.writes, request)
	return nil
}

func (s *fakeAGSRepositoryStore) PrunePages(_ context.Context, request wiki.KBWikiPrune) error {
	s.prunes = append(s.prunes, request)
	return nil
}

func (s *fakeAGSRepositoryStore) Reconcile(_ context.Context, repository repos.RepositoryIdentity) (wiki.KBWikiReconcileResult, error) {
	s.reconciled = true
	return wiki.KBWikiReconcileResult{RepositoryID: repository.ID, IndexedCommitSHA: "abc123", PageCount: len(s.writes), Reconciled: true}, nil
}

func (s *fakeAGSRepositoryStore) InitializeMemoryRepository(_ context.Context, request memory.MemoryRepositoryInitializeRequest) error {
	s.memoryInits = append(s.memoryInits, request)
	return s.memoryInitErr
}

func (s *fakeAGSRepositoryStore) ForkMemoryRepository(_ context.Context, request memory.MemoryRepositoryForkRequest) error {
	s.memoryForks = append(s.memoryForks, request)
	return s.memoryForkErr
}

type fakeSourceMirrorPreflighter struct {
	err     error
	request SourceMirrorPreflightRequest
	calls   int
}

func (f *fakeSourceMirrorPreflighter) PreflightSourceMirror(_ context.Context, request SourceMirrorPreflightRequest) error {
	f.calls++
	f.request = request
	if f.err != nil {
		return f.err
	}
	return nil
}
