package testkit

import (
	"context"
	"log/slog"
	"net/http"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/api/auth"
	"github.com/tidbcloud/AgentTeam/internal/api/daemon"
	"github.com/tidbcloud/AgentTeam/internal/api/im"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/binding"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/invocation"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/plan"
	"github.com/tidbcloud/AgentTeam/internal/api/workflow/run"
	"github.com/tidbcloud/AgentTeam/internal/api/workspace"
	"github.com/tidbcloud/AgentTeam/internal/archive"
	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/mailer"
	"github.com/tidbcloud/AgentTeam/internal/schedule"
	"github.com/tidbcloud/AgentTeam/internal/service/agentruntime"
	"github.com/tidbcloud/AgentTeam/internal/service/approvalapp"
	"github.com/tidbcloud/AgentTeam/internal/service/serviceaccount"
	"github.com/tidbcloud/AgentTeam/internal/sms"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"
	"github.com/tidbcloud/AgentTeam/internal/store/taskboard"
	"github.com/tidbcloud/AgentTeam/internal/trigger"
	"github.com/tidbcloud/AgentTeam/internal/unread"
	"github.com/tidbcloud/AgentTeam/internal/versioning"
)

type workflowBindingManagementService = binding.Service
type workflowInvocationManagementService = invocation.Service
type workflowPlanManagementService = plan.Service
type workflowPlanAgentEditService = plan.AgentEditService
type workflowRunManagementService = run.Service
type workflowCalendarService = run.CalendarService

type OrganizationProvider interface {
	ListOrganizationsForUser(ctx context.Context, userID string) ([]organization.OrganizationSummary, error)
	RequireOrganizationAdmin(ctx context.Context, userID string, organizationID string) error
	GetWorkspaceOrganizationForUser(ctx context.Context, userID string, workspaceID string) (organization.OrganizationSummary, error)
	PatchOrganizationForUser(ctx context.Context, userID string, organizationID string, params organization.UpdateOrganizationParams) (organization.OrganizationSummary, error)
	AutoJoinOrganizationsForVerifiedEmail(ctx context.Context, user organization.User) error
	AutoJoinOrganizationsForVerifiedMobile(ctx context.Context, user organization.User) error
	EnsureDefaultWorkspaceForUser(ctx context.Context, user organization.User) error
	HasPendingOrganizationInviteForEmail(ctx context.Context, email string) (bool, error)
	BuildFeishuLoginURL(ctx context.Context, organizationSlug string, redirectURI string) (string, error)
	AuthenticateFeishuLogin(ctx context.Context, code string, state string, redirectURI string) (organization.User, error)
	GetOrganizationSettingsForUser(ctx context.Context, userID string, organizationID string) (organization.OrganizationSettingsView, error)
	GetOrganizationHostedModelSettingsForUser(ctx context.Context, userID string, organizationID string) (organization.OrganizationHostedModelSettingsView, error)
	GetHostedModelSelectionForWorkspace(ctx context.Context, organizationID string, workspaceID string) (organization.OrganizationHostedModelSelectionView, error)
	GetOrganizationDirectorySyncRunForUser(ctx context.Context, userID string, organizationID string, syncRunID string) (organization.OrganizationDirectorySyncRunDetailView, error)
	GetOrganizationEnterpriseFeishuForUser(ctx context.Context, userID string, organizationID string) (organization.OrganizationEnterpriseFeishuView, error)
	UpdateOrganizationEnterpriseFeishuCredentialsForUser(ctx context.Context, userID string, organizationID string, appID string, appSecret string) (organization.OrganizationEnterpriseFeishuView, error)
	DeleteOrganizationEnterpriseFeishuCredentialsForUser(ctx context.Context, userID string, organizationID string) (organization.OrganizationEnterpriseFeishuView, error)
	PatchOrganizationSettingsForUser(ctx context.Context, userID string, organizationID string, params organization.UpdateOrganizationSettingsParams) (organization.OrganizationSettingsView, error)
	PatchOrganizationHostedModelSettingsForUser(ctx context.Context, userID string, organizationID string, params organization.UpdateOrganizationHostedModelSettingsParams) (organization.OrganizationHostedModelSettingsView, error)
	StartOrganizationFeishuDirectorySyncForUser(ctx context.Context, userID string, organizationID string) (organization.OrganizationDirectorySyncRunSummaryView, bool, error)
	RunOrganizationFeishuDirectorySyncForUser(ctx context.Context, userID string, organizationID string, syncRunID string) (organization.OrganizationFeishuDirectoryImportResult, error)
	SyncOrganizationFeishuDirectoryForUser(ctx context.Context, userID string, organizationID string) (organization.OrganizationFeishuDirectoryImportResult, error)
	UpdateOrganizationSettingsForUser(ctx context.Context, userID string, organizationID string, directoryBackend string) (organization.OrganizationSettingsView, error)
	ListOrganizationInvitesForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationInviteView, error)
	CreateOrganizationInviteForUser(ctx context.Context, userID string, organizationID string, params organization.CreateOrganizationInviteParams, tokenHash string, expiresAt time.Time) (organization.OrganizationInviteView, error)
	RevokeOrganizationInviteForUser(ctx context.Context, userID string, organizationID string, inviteID string) error
	FindOrganizationInviteInfoByToken(ctx context.Context, token string) (organization.OrganizationInviteInfo, bool, error)
	AcceptOrganizationInviteByTokenIfExists(ctx context.Context, user organization.User, token string) (organization.OrganizationInviteAcceptance, bool, error)
	ListOrganizationUnitsForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationUnitView, error)
	CreateOrganizationUnitForUser(ctx context.Context, userID string, organizationID string, params organization.CreateOrganizationUnitParams) (organization.OrganizationUnitView, error)
	ListOrganizationUnitMembersForUser(ctx context.Context, userID string, organizationID string, unitID string) ([]organization.OrganizationUnitMemberView, error)
	AddOrganizationUnitMemberForUser(ctx context.Context, userID string, organizationID string, unitID string, params organization.AddOrganizationUnitMemberParams) (organization.OrganizationUnitMemberView, error)
	RemoveOrganizationUnitMemberForUser(ctx context.Context, userID string, organizationID string, unitID string, memberID string) error
	ListOrganizationMemberUnitsForUser(ctx context.Context, userID string, organizationID string, memberID string) ([]organization.OrganizationMemberUnitView, error)
	ListOrganizationTeamsForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationTeamView, error)
	CreateOrganizationTeamForUser(ctx context.Context, userID string, organizationID string, name string, slug string, description string) (organization.OrganizationTeamView, error)
	ListOrganizationTeamMembersForUser(ctx context.Context, userID string, organizationID string, teamID string) ([]organization.OrganizationTeamMemberView, error)
	AddOrganizationTeamMemberForUser(ctx context.Context, userID string, organizationID string, teamID string, params organization.AddOrganizationTeamMemberParams) (organization.OrganizationTeamMemberView, error)
	RemoveOrganizationTeamMemberForUser(ctx context.Context, userID string, organizationID string, teamID string, memberID string) error
	SwitchOrganizationMemberPrimaryTeamForUser(ctx context.Context, userID string, organizationID string, memberID string, teamID string) (organization.OrganizationMemberView, error)
	ListOrganizationMembersForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationMemberView, error)
	ListOrganizationMembersForUserPage(ctx context.Context, userID string, organizationID string, options organization.OrganizationMemberListOptions) (organization.OrganizationMemberPage, error)
	CreateOrganizationMemberForUser(ctx context.Context, userID string, organizationID string, teamID string, email string, defaultWorkspaceRole string) (organization.OrganizationMemberView, error)
	UpdateOrganizationMemberRoleForUser(ctx context.Context, userID string, organizationID string, accountID string, role string) (organization.OrganizationMemberView, error)
	PreviewOrganizationMemberRemovalImpactForUser(ctx context.Context, userID string, organizationID string, memberID string) (organization.OrganizationMemberRemovalImpact, error)
	RemoveOrganizationMemberForUser(ctx context.Context, userID string, organizationID string, memberID string) (organization.OrganizationMemberRemovalResult, error)
	ListOrganizationWorkspacesForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationWorkspaceView, error)
	CreateOrganizationWorkspaceForUser(ctx context.Context, userID string, organizationID string, name string, slug string) (organization.OrganizationWorkspaceView, error)
	ListOrganizationProvidersForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationProviderView, error)
	ListOrganizationProviderRoutesForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationProviderRouteView, error)
	CreateOrganizationProviderRouteForUser(ctx context.Context, userID string, organizationID string, params organization.CreateOrganizationProviderRouteParams) (organization.OrganizationProviderRouteView, error)
	UpdateOrganizationProviderRouteForUser(ctx context.Context, userID string, organizationID string, routeID string, params organization.UpdateOrganizationProviderRouteParams) (organization.OrganizationProviderRouteView, error)
	DeleteOrganizationProviderRouteForUser(ctx context.Context, userID string, organizationID string, routeID string) error
	ListOrganizationProviderRouteGroupsForUser(ctx context.Context, userID string, organizationID string, routeID string) ([]organization.OrganizationProviderRouteGroupView, error)
	CreateOrganizationProviderRouteGroupForUser(ctx context.Context, userID string, organizationID string, routeID string, params organization.CreateOrganizationProviderRouteGroupParams) (organization.OrganizationProviderRouteGroupView, error)
	UpdateOrganizationProviderRouteGroupForUser(ctx context.Context, userID string, organizationID string, routeID string, groupID string, params organization.UpdateOrganizationProviderRouteGroupParams) (organization.OrganizationProviderRouteGroupView, error)
	DeleteOrganizationProviderRouteGroupForUser(ctx context.Context, userID string, organizationID string, routeID string, groupID string) error
	GetOrganizationProviderForUser(ctx context.Context, userID string, organizationID string, providerID string) (organization.OrganizationProviderView, error)
	CreateOrganizationProviderForUser(ctx context.Context, userID string, organizationID string, params organization.CreateOrganizationProviderParams) (organization.OrganizationProviderView, error)
	UpdateOrganizationProviderForUser(ctx context.Context, userID string, organizationID string, providerID string, params organization.UpdateOrganizationProviderParams) (organization.OrganizationProviderView, error)
	DeleteOrganizationProviderForUser(ctx context.Context, userID string, organizationID string, providerID string) error
	ListOrganizationProviderTokensForUser(ctx context.Context, userID string, organizationID string, providerID string) ([]organization.OrganizationProviderTokenView, error)
	CreateOrganizationProviderTokenForUser(ctx context.Context, userID string, organizationID string, providerID string, params organization.CreateOrganizationProviderTokenParams) (organization.OrganizationProviderTokenView, error)
	DeleteOrganizationProviderTokenForUser(ctx context.Context, userID string, organizationID string, providerID string, tokenID string) error
	ListOrganizationLLMProxyKeysForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationLLMProxyKeyView, error)
	CreateOrganizationLLMProxyKeyForUser(ctx context.Context, userID string, organizationID string, params organization.CreateOrganizationLLMProxyKeyParams) (organization.OrganizationLLMProxyKeyCreateResult, error)
	DeleteOrganizationLLMProxyKeyForUser(ctx context.Context, userID string, organizationID string, keyID string) error
	ListOrganizationLLMStatsSummaryForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationLLMStatsSummaryView, error)
	ListOrganizationLLMStatsDetailForUser(ctx context.Context, userID string, organizationID string, query organization.OrganizationLLMStatsQuery) ([]organization.OrganizationLLMStatsDetailView, error)
	GetOrganizationLLMStatsTimeSeriesForUser(ctx context.Context, userID string, organizationID string, query organization.OrganizationLLMStatsQuery) (organization.OrganizationLLMTimeSeriesView, error)
	GetOrganizationLLMErrorSummaryForUser(ctx context.Context, userID string, organizationID string, query organization.OrganizationLLMStatsQuery) (organization.OrganizationLLMErrorSummaryView, error)
	GetOrganizationLLMErrorTimeSeriesForUser(ctx context.Context, userID string, organizationID string, query organization.OrganizationLLMStatsQuery) (organization.OrganizationLLMErrorTimeSeriesView, error)
	ListOrganizationLLMQuotaPoliciesForUser(ctx context.Context, userID string, organizationID string) ([]organization.OrganizationLLMQuotaPolicyView, error)
	UpsertOrganizationLLMQuotaPolicyForUser(ctx context.Context, userID string, organizationID string, params organization.UpsertOrganizationLLMQuotaPolicyParams) (organization.OrganizationLLMQuotaPolicyView, error)
	DeleteOrganizationLLMQuotaPolicyForUser(ctx context.Context, userID string, organizationID string, subjectType string, subjectID string) error
	CreateInternalWorkspaceProxyKey(ctx context.Context, workspaceID string, expiresAt time.Time) (string, error)
	ListOrganizationWorkspaceProviderGrantsForUser(ctx context.Context, userID string, organizationID string, workspaceID string) ([]organization.OrganizationWorkspaceProviderGrantView, error)
	ListOrganizationWorkspaceRouteGrantsForUser(ctx context.Context, userID string, organizationID string, workspaceID string) ([]organization.OrganizationWorkspaceRouteGrantView, error)
	GrantOrganizationWorkspaceProviderForUser(ctx context.Context, userID string, organizationID string, workspaceID string, providerID string) (organization.OrganizationWorkspaceProviderGrantView, error)
	GrantOrganizationWorkspaceRouteForUser(ctx context.Context, userID string, organizationID string, workspaceID string, routeID string) (organization.OrganizationWorkspaceRouteGrantView, error)
	RevokeOrganizationWorkspaceProviderForUser(ctx context.Context, userID string, organizationID string, workspaceID string, providerID string) error
	RevokeOrganizationWorkspaceRouteForUser(ctx context.Context, userID string, organizationID string, workspaceID string, routeID string) error
	GetOrganizationWorkspaceHostedModelAuthorizationForUser(ctx context.Context, userID string, organizationID string, workspaceID string) (organization.OrganizationWorkspaceHostedModelAuthorizationView, error)
	PreviewOrganizationWorkspaceHostedModelAuthorizationForUser(ctx context.Context, userID string, organizationID string, workspaceID string, params organization.UpsertOrganizationWorkspaceHostedModelAuthorizationParams) (organization.OrganizationWorkspaceHostedModelAuthorizationView, error)
	UpsertOrganizationWorkspaceHostedModelAuthorizationForUser(ctx context.Context, userID string, organizationID string, workspaceID string, params organization.UpsertOrganizationWorkspaceHostedModelAuthorizationParams) (organization.OrganizationWorkspaceHostedModelAuthorizationView, error)
	ListVisibleOrganizationProvidersForWorkspace(ctx context.Context, workspaceID string) ([]organization.OrganizationProviderView, error)
	ListOrganizationWorkspaceGrantsForUser(ctx context.Context, userID string, organizationID string, workspaceID string) ([]organization.OrganizationWorkspaceGrantView, error)
	GrantOrganizationMemberWorkspaceAccessForUser(ctx context.Context, userID string, organizationID string, workspaceID string, accountID string, role string) (organization.OrganizationWorkspaceGrantView, error)
	RevokeOrganizationMemberWorkspaceAccessForUser(ctx context.Context, userID string, organizationID string, workspaceID string, accountID string) error
	ListOrganizationWorkspaceTeamGrantsForUser(ctx context.Context, userID string, organizationID string, workspaceID string) ([]organization.OrganizationWorkspaceTeamGrantView, error)
	GrantOrganizationTeamWorkspaceAccessForUser(ctx context.Context, userID string, organizationID string, workspaceID string, teamID string, role string) (organization.OrganizationWorkspaceTeamGrantView, error)
	RevokeOrganizationTeamWorkspaceAccessForUser(ctx context.Context, userID string, organizationID string, workspaceID string, teamID string) error
	ListWorkspaceMemberAccessSources(ctx context.Context, workspaceID string) ([]organization.WorkspaceMemberAccessSourceView, error)
	ListWorkspaceMemberAccessSourcesForUsers(ctx context.Context, workspaceID string, userIDs []string) ([]organization.WorkspaceMemberAccessSourceView, error)
}

type LLMRegistry interface {
	Refresh(ctx context.Context) error
}

// Runtime is an integration-test fixture for composing domain HTTP routes.
// It intentionally exposes concrete test collaborators instead of pretending to be
// the removed production legacy route facade.
type Runtime struct {
	Ctx                       context.Context
	Pool                      coredb.DB
	ArchiveStorage            archive.Storage
	Logger                    *slog.Logger
	Store                     *Store
	Organizations             OrganizationProvider
	HostedAvailability        workspace.HostedAvailabilityClient
	TaskBoard                 *taskboard.Store
	Mailer                    mailer.Mailer
	MobileVerificationSender  sms.Sender
	AgentRuntime              *agentruntime.Service
	Hub                       *daemon.Hub
	LiveEmitter               *im.LiveEventEmitter
	UnreadRuntime             *unread.Service
	PublicBaseURL             string
	GitHubFlowStateKey        []byte
	GitHubBaseURL             string
	GitHubAPIBaseURL          string
	HTTPClient                *http.Client
	EmailVerificationRequired bool
	RegistrationPolicy        auth.RegistrationPolicy
	VerificationTokenTTL      time.Duration
	SessionTTL                time.Duration
	HotMessageRetentionDays   int
	DaemonConnectBaseURL      string
	MeshXEnabled              bool
	MeshXBaseURL              string
	LatestDaemonVersion       versioning.Provider
	LLMRegistry               LLMRegistry
	PasswordAuthDisabled      bool
	Triggers                  *trigger.Service
	Schedules                 *schedule.Service
	WorkflowBinding           workflowBindingManagementService
	WorkflowInvocation        workflowInvocationManagementService
	WorkflowPlan              workflowPlanManagementService
	WorkflowPlanAgentEdit     workflowPlanAgentEditService
	WorkflowRun               workflowRunManagementService
	WorkflowCalendar          workflowCalendarService
	ServiceAccount            *serviceaccount.Service
	PlatformServiceAccount    *serviceaccount.PlatformService
	ApprovalAppProjector      *approvalapp.Projector
	PingCAPAuthConfig         auth.PingCAPAuthConfig
}

func (runtime *Runtime) SetRegistrationPolicy(policy auth.RegistrationPolicy) {
	runtime.RegistrationPolicy = policy
}

func (runtime *Runtime) SetTriggerService(triggerService *trigger.Service) {
	runtime.Triggers = triggerService
}

func (runtime *Runtime) SetScheduleService(scheduleService *schedule.Service) {
	runtime.Schedules = scheduleService
}

func (runtime *Runtime) SetMeshXBaseURL(baseURL string) {
	runtime.MeshXBaseURL = strings.TrimSpace(baseURL)
}

func (runtime *Runtime) SetMeshXEnabled(enabled bool) {
	runtime.MeshXEnabled = enabled
}

func (runtime *Runtime) StartBackgroundWorkers(ctx context.Context) {
	if runtime.PlatformServiceAccount != nil {
		go runtime.PlatformServiceAccount.Run(ctx, time.Second)
	}
}
