package automation

import (
	"context"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/content"
)

// AuthorityRoutedAutomationSource is the Automation-owned one-way cutover
// seam. Missing authority rows remain legacy. Native failures never fall back
// to AGS, so a restarted process cannot reverse an activated binding.
type AuthorityRoutedAutomationSource struct {
	NativeEnabled bool
	Authority     AutomationContentAuthority
	Legacy        interface {
		AutomationSourceResolver
		AutomationSourceControlPlane
		AutomationSourceWriteControlPlane
	}
	Native interface {
		AutomationSourceResolver
		AutomationSourceControlPlane
		AutomationSourceWriteControlPlane
	}
}

func (source AuthorityRoutedAutomationSource) ResolveAutomationSource(ctx context.Context, request AutomationSourceRequest) (AutomationSourceSnapshot, error) {
	routed, err := source.route(ctx, request.WorkspaceID, request.RepositoryOwner, request.RepositoryName)
	if err != nil {
		return AutomationSourceSnapshot{}, err
	}
	return routed.ResolveAutomationSource(ctx, request)
}

func (source AuthorityRoutedAutomationSource) ListAutomationRepositories(ctx context.Context, authorizationHeader string, page, perPage int) ([]AutomationSourceRepository, error) {
	if source.Legacy == nil {
		return nil, fmt.Errorf("legacy automation source is not configured")
	}
	return source.Legacy.ListAutomationRepositories(ctx, authorizationHeader, page, perPage)
}

func (source AuthorityRoutedAutomationSource) ListAutomationOrgRepositories(ctx context.Context, authorizationHeader, org string, page, perPage int) ([]AutomationSourceRepository, error) {
	if source.Legacy == nil {
		return nil, fmt.Errorf("legacy automation source is not configured")
	}
	legacy, err := source.Legacy.ListAutomationOrgRepositories(ctx, authorizationHeader, org, page, perPage)
	if err != nil {
		return nil, err
	}
	if !source.NativeEnabled || source.Native == nil {
		return legacy, nil
	}
	native, err := source.Native.ListAutomationOrgRepositories(ctx, authorizationHeader, org, page, perPage)
	if err != nil {
		return nil, err
	}
	return append(legacy, native...), nil
}

func (source AuthorityRoutedAutomationSource) ListAutomationFiles(ctx context.Context, request AutomationSourceRequest) ([]AutomationSourceFile, error) {
	routed, err := source.route(ctx, request.WorkspaceID, request.RepositoryOwner, request.RepositoryName)
	if err != nil {
		return nil, err
	}
	return routed.ListAutomationFiles(ctx, request)
}

func (source AuthorityRoutedAutomationSource) GetAutomationFile(ctx context.Context, request AutomationSourceRequest) (AutomationSourceContent, error) {
	routed, err := source.route(ctx, request.WorkspaceID, request.RepositoryOwner, request.RepositoryName)
	if err != nil {
		return AutomationSourceContent{}, err
	}
	return routed.GetAutomationFile(ctx, request)
}

func (source AuthorityRoutedAutomationSource) PutAutomationFile(ctx context.Context, request AutomationSourceWriteRequest) (AutomationSourceWriteResult, error) {
	routed, err := source.route(ctx, request.WorkspaceID, request.RepositoryOwner, request.RepositoryName)
	if err != nil {
		return AutomationSourceWriteResult{}, err
	}
	return routed.PutAutomationFile(ctx, request)
}

func (source AuthorityRoutedAutomationSource) DeleteAutomationFile(ctx context.Context, request AutomationSourceDeleteRequest) error {
	routed, err := source.route(ctx, request.WorkspaceID, request.RepositoryOwner, request.RepositoryName)
	if err != nil {
		return err
	}
	return routed.DeleteAutomationFile(ctx, request)
}

func (source AuthorityRoutedAutomationSource) route(ctx context.Context, workspaceID, owner, repository string) (interface {
	AutomationSourceResolver
	AutomationSourceControlPlane
	AutomationSourceWriteControlPlane
}, error) {
	if source.Authority == nil || source.Legacy == nil {
		return nil, fmt.Errorf("automation content authority is not configured")
	}
	bindingKey := automationRepositoryBindingKey(owner, repository)
	if strings.TrimSpace(workspaceID) == "" || bindingKey == "" {
		return nil, fmt.Errorf("automation content binding is invalid")
	}
	authority, found, err := source.Authority.GetAuthority(ctx, workspaceID, "automation", bindingKey)
	if err != nil {
		return nil, fmt.Errorf("resolve automation content authority: %w", err)
	}
	state := content.AuthorityStateLegacyActive
	if found {
		state = strings.TrimSpace(authority.State)
	}
	switch state {
	case content.AuthorityStateLegacyActive:
		return source.Legacy, nil
	case content.AuthorityStateNativeActive:
		if !source.NativeEnabled || source.Native == nil {
			return nil, fmt.Errorf("native automation content is unavailable")
		}
		return source.Native, nil
	default:
		return nil, fmt.Errorf("unknown automation content authority state %q", state)
	}
}

// AuthorityRoutedAutomationRepositoryCredentialChecker preserves AGS checkout
// readiness only for legacy bindings. Native runs carry exact ContentVersion
// provenance and do not require an AGS repository credential.
type AuthorityRoutedAutomationRepositoryCredentialChecker struct {
	NativeEnabled bool
	Authority     AutomationContentAuthority
	Legacy        AutomationRepositoryCredentialChecker
}

func (checker AuthorityRoutedAutomationRepositoryCredentialChecker) CheckAutomationRepositoryCredential(ctx context.Context, request AutomationRepositoryCredentialCheckRequest) (AutomationRepositoryCredentialAvailability, error) {
	if checker.Authority == nil || checker.Legacy == nil {
		return AutomationRepositoryCredentialAvailability{}, fmt.Errorf("automation repository credential authority is not configured")
	}
	bindingKey := automationRepositoryBindingKey(request.RepositoryOwner, request.RepositoryName)
	authority, found, err := checker.Authority.GetAuthority(ctx, request.WorkspaceID, "automation", bindingKey)
	if err != nil {
		return AutomationRepositoryCredentialAvailability{}, fmt.Errorf("resolve automation credential authority: %w", err)
	}
	if !found || authority.State == content.AuthorityStateLegacyActive {
		return checker.Legacy.CheckAutomationRepositoryCredential(ctx, request)
	}
	if authority.State != content.AuthorityStateNativeActive || !checker.NativeEnabled {
		return AutomationRepositoryCredentialAvailability{}, fmt.Errorf("native automation credential route is unavailable")
	}
	return AutomationRepositoryCredentialAvailability{RepoTokenAvailable: true, RepoTokenScope: "content_version"}, nil
}

func automationRepositoryBindingKey(owner, repository string) string {
	owner = strings.TrimSpace(owner)
	repository = strings.TrimSpace(repository)
	if owner == "" || repository == "" {
		return ""
	}
	return owner + "/" + repository
}

var _ AutomationSourceResolver = AuthorityRoutedAutomationSource{}
var _ AutomationSourceControlPlane = AuthorityRoutedAutomationSource{}
var _ AutomationSourceWriteControlPlane = AuthorityRoutedAutomationSource{}
var _ AutomationRepositoryCredentialChecker = AuthorityRoutedAutomationRepositoryCredentialChecker{}
