// Package admin contains system-admin browser API routes.
package admin

import (
	"context"
	"log/slog"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/service/serviceaccount"
	"github.com/tidbcloud/AgentTeam/internal/store/admin"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
	serviceaccountstore "github.com/tidbcloud/AgentTeam/internal/store/serviceaccount"
	"github.com/tidbcloud/AgentTeam/internal/store/workspace"
)

// AuthStore is the shared browser-app auth middleware port.
type AuthStore interface {
	api.SessionAuthenticator
}

// AdminStore is the system-admin dashboard storage port.
type AdminStore interface {
	ListAdminUsers(ctx context.Context, userID string, query string, since time.Time, active bool, limit int) ([]admin.AdminUserSummary, error)
	ListAdminWorkspaces(ctx context.Context, userID string, query string, since time.Time, active bool, limit int) ([]admin.AdminWorkspaceSummary, error)
	LoadAdminOverview(ctx context.Context, userID string, since time.Time) (admin.AdminOverview, error)
}

// RegistrationAllowlistStore is the system-admin registration allowlist port.
type RegistrationAllowlistStore interface {
	CreateRegistrationAllowlistEntryForUser(ctx context.Context, userID string, pattern string, reason string, expiresAt *time.Time) (identity.RegistrationAllowlistEntry, error)
	DisableRegistrationAllowlistEntryForUser(ctx context.Context, userID string, entryID string) (identity.RegistrationAllowlistEntry, error)
	ListRegistrationAllowlistEntriesForUser(ctx context.Context, userID string, query string, includeDisabled bool) ([]identity.RegistrationAllowlistEntry, error)
}

// HostedCreditGrantClient is the system-admin bridge to agentteam-maas hosted credit grants.
type HostedCreditGrantClient interface {
	GrantHostedCredit(ctx context.Context, params HostedCreditGrantParams) (HostedCreditGrant, error)
}

// HostedCreditGrantParams creates an operator-originated hosted credit grant.
type HostedCreditGrantParams struct {
	OrganizationID    string
	IdempotencyKey    string
	CreditUnit        string
	CreditAmount      int64
	CreditAmountAtoms int64
	GrantSourceType   string
	GrantReasonRef    string
	Refundable        bool
	ExpiresAt         *time.Time
	OperatorIdentity  string
	SourceRef         string
}

// HostedCreditGrant is the system-admin hosted credit grant view returned by the bridge.
type HostedCreditGrant struct {
	GrantID           string
	OperationID       string
	Created           bool
	OrganizationID    string
	CreditUnit        string
	CreditAmount      int64
	CreditAmountAtoms int64
	GrantSourceType   string
	GrantReasonRef    string
	Refundable        bool
	ExpiresAt         *time.Time
	OperatorIdentity  string
	SourceRef         string
	CreatedAt         time.Time
	UpdatedAt         time.Time
}

// HostedCreditGrantServiceError carries an upstream service HTTP status.
type HostedCreditGrantServiceError struct {
	StatusCode int
	Cause      error
}

func (err HostedCreditGrantServiceError) Error() string {
	if err.Cause != nil {
		return err.Cause.Error()
	}
	return "hosted credit grant service error"
}

func (err HostedCreditGrantServiceError) Unwrap() error {
	return err.Cause
}

// DatabasePoolController is the system-admin runtime DB pool control surface.
type DatabasePoolController interface {
	Snapshot() coredb.DBPoolSnapshot
	Update(coredb.DBPoolConfig) (coredb.DBPoolSnapshot, error)
}

// WorkspacePlacementAdminStore is the internal service admin placement surface.
type WorkspacePlacementAdminStore interface {
	ListWorkspaceGroups(ctx context.Context) ([]workspace.WorkspaceGroup, error)
	CreateWorkspaceGroup(ctx context.Context, request workspace.CreateWorkspaceGroupRequest) (workspace.WorkspaceGroup, error)
	DisableWorkspaceGroup(ctx context.Context, workspaceGroupID string) (workspace.WorkspaceGroup, error)
	ListWorkspacePlacements(ctx context.Context, filter workspace.WorkspacePlacementListFilter) ([]workspace.WorkspacePlacement, error)
	VerifyWorkspacePlacementTopology(ctx context.Context) (workspace.WorkspacePlacementTopologyVerification, error)
	StartWorkspacePlacementMigration(ctx context.Context, request workspace.StartWorkspacePlacementMigrationRequest) (workspace.WorkspacePlacementMigration, error)
	GetActiveWorkspacePlacementMigration(ctx context.Context, workspaceID string) (*workspace.WorkspacePlacementMigration, error)
	GetWorkspacePlacementMigration(ctx context.Context, migrationID string) (workspace.WorkspacePlacementMigration, error)
	MoveWorkspacePlacementMigration(ctx context.Context, migrationID string) (workspace.WorkspacePlacementMigration, error)
	CompleteWorkspacePlacementMigration(ctx context.Context, migrationID string) (workspace.WorkspacePlacementMigration, error)
	RollbackWorkspacePlacementMigration(ctx context.Context, migrationID string) (workspace.WorkspacePlacementMigration, error)
}

// PlatformServiceAccountService is the system-admin control surface for
// deployment-global Service Accounts and their cross-workspace broadcasts.
type PlatformServiceAccountService interface {
	CreatePlatformAccount(context.Context, serviceaccount.PlatformAccountCreate) (serviceaccountstore.PlatformAccount, error)
	GetPlatformAccount(context.Context, string) (serviceaccountstore.PlatformAccount, error)
	ListPlatformAccounts(context.Context, string, string, int) ([]serviceaccountstore.PlatformAccount, error)
	DeletePlatformAccount(context.Context, serviceaccount.PlatformAccountDelete) (serviceaccountstore.PlatformAccount, error)
	UpdatePlatformAccountAvatar(context.Context, serviceaccount.PlatformAccountAvatarMutation) (serviceaccountstore.PlatformAccount, error)
	SubmitPlatformBroadcast(context.Context, serviceaccount.PlatformBroadcastSubmit) (serviceaccountstore.PlatformBroadcast, error)
	GetPlatformBroadcast(context.Context, string, string) (serviceaccountstore.PlatformBroadcast, error)
	ListPlatformBroadcasts(context.Context, string, string, int) ([]serviceaccountstore.PlatformBroadcast, error)
	ListPlatformBroadcastItems(context.Context, string, string, string, int) ([]serviceaccount.PlatformBroadcastListItem, error)
	ProcessOnce(context.Context) (serviceaccount.PlatformProcessResult, error)
}

// Store is the legacy composite storage port used by tests and compatibility wiring.
type Store interface {
	AuthStore
	AdminStore
	RegistrationAllowlistStore
}

// Dependencies contains collaborators and config for system-admin routes.
type Dependencies struct {
	AuthStore                 AuthStore
	Store                     Store
	AdminStore                AdminStore
	RegistrationAllowlist     RegistrationAllowlistStore
	HostedCreditGrants        HostedCreditGrantClient
	DatabasePool              DatabasePoolController
	WorkspacePlacementAdmin   WorkspacePlacementAdminStore
	PlatformServiceAccounts   PlatformServiceAccountService
	InternalAdminToken        string
	EmailVerificationRequired bool
	Logger                    *slog.Logger
}

// RegisterRoutes mounts system-admin routes.
func RegisterRoutes(router gin.IRouter, dependencies Dependencies) {
	if router == nil {
		return
	}
	admin := router.Group(
		"/api/v1/admin",
		api.RequireAuthenticatedUser(adminAuthStore(dependencies)),
		api.RequireVerifiedIdentity(dependencies.EmailVerificationRequired),
		api.RequirePlatformOperator(),
	)
	registerAdminRoutes(admin, dependencies)
}

func registerAdminRoutes(admin gin.IRoutes, dependencies Dependencies) {
	handler := &SystemAdminHandler{
		adminStore:              adminDashboardStore(dependencies),
		allowlistStore:          adminRegistrationAllowlistStore(dependencies),
		creditGrants:            dependencies.HostedCreditGrants,
		dbPool:                  dependencies.DatabasePool,
		platformServiceAccounts: dependencies.PlatformServiceAccounts,
	}
	admin.GET("/overview", api.HandleAuth(handler.Overview))
	admin.GET("/workspaces", api.HandleAuth(handler.ListWorkspaces))
	admin.GET("/users", api.HandleAuth(handler.ListUsers))
	admin.GET("/registration-allowlist", api.HandleAuth(handler.ListRegistrationAllowlist))
	admin.POST("/registration-allowlist", api.HandleAuthJSON[dto.AdminRegistrationAllowlistCreateRequest](handler.CreateRegistrationAllowlist))
	admin.POST("/registration-allowlist/:entryId/disable", api.HandleAuth(handler.DisableRegistrationAllowlist))
	admin.POST("/orgs/:orgId/hosted-credit-grants", api.HandleAuthJSON[dto.AdminHostedCreditGrantCreateRequest](handler.GrantHostedCredit))
	admin.GET("/runtime/db-pool", api.HandleAuth(handler.LoadDatabasePool))
	admin.PATCH("/runtime/db-pool", api.HandleAuthJSON[dto.AdminDBPoolPatchRequest](handler.PatchDatabasePool))
	admin.GET("/platform-service-accounts", api.HandleAuth(handler.ListPlatformServiceAccounts))
	admin.POST("/platform-service-accounts", api.HandleAuthJSON[dto.AdminPlatformServiceAccountCreateRequest](handler.CreatePlatformServiceAccount))
	admin.GET("/platform-service-accounts/:platformServiceAccountId", api.HandleAuth(handler.GetPlatformServiceAccount))
	admin.PATCH("/platform-service-accounts/:platformServiceAccountId/avatar", api.HandleAuthJSON[dto.AdminPlatformServiceAccountAvatarUpdateRequest](handler.UpdatePlatformServiceAccountAvatar))
	admin.DELETE("/platform-service-accounts/:platformServiceAccountId", api.HandleAuth(handler.DeletePlatformServiceAccount))
	admin.POST("/platform-service-accounts/:platformServiceAccountId/reconcile", api.HandleAuth(handler.ReconcilePlatformServiceAccounts))
	admin.GET("/platform-service-accounts/:platformServiceAccountId/broadcasts", api.HandleAuth(handler.ListPlatformBroadcasts))
	admin.POST("/platform-service-accounts/:platformServiceAccountId/broadcasts", api.HandleAuthJSON[dto.AdminPlatformBroadcastCreateRequest](handler.CreatePlatformBroadcast))
	admin.GET("/platform-service-accounts/:platformServiceAccountId/broadcasts/:broadcastId", api.HandleAuth(handler.GetPlatformBroadcast))
}

// RegisterInternalRoutes mounts private service-admin placement routes.
func RegisterInternalRoutes(router gin.IRouter, dependencies Dependencies) {
	if router == nil {
		return
	}
	internal := router.Group(
		"/internal/admin",
		api.RequireInternalAdminCredential(dependencies.InternalAdminToken),
	)
	handler := &InternalAdminHandler{store: dependencies.WorkspacePlacementAdmin}
	internal.GET("/workspace-groups", handler.ListWorkspaceGroups)
	internal.POST("/workspace-groups", handler.CreateWorkspaceGroup)
	internal.POST("/workspace-groups/:groupId/disable", handler.DisableWorkspaceGroup)
	internal.GET("/workspace-placements", handler.ListWorkspacePlacements)
	internal.POST("/workspace-placements/verify", handler.VerifyWorkspacePlacements)
	internal.POST("/workspace-migrations", handler.StartWorkspaceMigration)
	internal.GET("/workspace-migrations/active", handler.GetActiveWorkspaceMigration)
	internal.GET("/workspace-migrations/:migrationId", handler.GetWorkspaceMigration)
	internal.POST("/workspace-migrations/:migrationId/move", handler.MoveWorkspaceMigration)
	internal.POST("/workspace-migrations/:migrationId/complete", handler.CompleteWorkspaceMigration)
	internal.POST("/workspace-migrations/:migrationId/rollback", handler.RollbackWorkspaceMigration)
}

func adminAuthStore(dependencies Dependencies) AuthStore {
	if dependencies.AuthStore != nil {
		return dependencies.AuthStore
	}
	return dependencies.Store
}

func adminDashboardStore(dependencies Dependencies) AdminStore {
	if dependencies.AdminStore != nil {
		return dependencies.AdminStore
	}
	return dependencies.Store
}

func adminRegistrationAllowlistStore(dependencies Dependencies) RegistrationAllowlistStore {
	if dependencies.RegistrationAllowlist != nil {
		return dependencies.RegistrationAllowlist
	}
	return dependencies.Store
}
