// Package serviceaccount owns persistence for workspace service accounts,
// platform service-account principals, creation requests, Human manager
// assignments, name claims, platform workspace bindings, and audit facts.
// Ordinary messages, audience memberships, notification preferences, and read
// state remain owned by the shared message domain.
package serviceaccount

import (
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

const (
	ServiceDefinitionID = "svcdef_service_account"
	ServiceKind         = "service_account"

	ManagementKindWorkspace = "workspace"
	ManagementKindPlatform  = "platform"

	AudienceStatePending     = "pending"
	AudienceStateReconciling = "reconciling"
	AudienceStateReady       = "ready"
	AudienceStateFailed      = "failed"

	ManagerStatusActive = "active"
	ManagerStatusEnded  = "ended"

	AuthorizationPathDirectCreate     = "direct_create"
	AuthorizationPathApprovalRequired = "approval_required"

	RequestStateSubmitted             = "submitted"
	RequestStateAwaitingAuthorization = "awaiting_authorization"
	RequestStateAuthorized            = "authorized"
	RequestStateDeclined              = "declined"
	RequestStateCancelled             = "cancelled"
	RequestStateProvisioning          = "provisioning"
	RequestStateFulfilled             = "fulfilled"
	RequestStateActionRequired        = "action_required"

	PlatformProvisioningStatePending       = "pending"
	PlatformProvisioningStateIdentityReady = "identity_ready"
	PlatformProvisioningStateApplied       = "applied"
	PlatformProvisioningStateClosed        = "closed"

	PlatformProvisioningSourceAccountCreate   = "account_create"
	PlatformProvisioningSourceWorkspaceCreate = "workspace_create"
	PlatformProvisioningSourceReconcile       = "reconcile"

	PlatformBroadcastStateWaitingProvisioning = "waiting_provisioning"
	PlatformBroadcastStateAccepted            = "accepted"
	PlatformBroadcastStateDispatching         = "dispatching"
	PlatformBroadcastStateCompleted           = "completed"
	PlatformBroadcastStateCompletedExceptions = "completed_with_exceptions"
	PlatformBroadcastStateClosed              = "closed"

	PlatformDeliveryStateQueued            = "queued"
	PlatformDeliveryStateLeased            = "leased"
	PlatformDeliveryStateWaitingInstance   = "waiting_instance"
	PlatformDeliveryStateWaitingAudience   = "waiting_audience"
	PlatformDeliveryStateRetryWait         = "retry_wait"
	PlatformDeliveryStateOperatorAttention = "operator_attention"
	PlatformDeliveryStateDelivered         = "delivered"
	PlatformDeliveryStateClosed            = "closed"
	PlatformDeliveryStateSkipped           = "skipped"

	PlatformDeliveryOutcomeDelivered          = "delivered"
	PlatformDeliveryOutcomeGenerationExcluded = "generation_excluded"
	PlatformDeliveryOutcomeRetryExhausted     = "retry_exhausted"
)

var (
	ErrNotFound   = storeerr.ErrNotFound
	ErrConflict   = storeerr.ErrConflict
	ErrBadRequest = storeerr.ErrBadRequest
)

func badRequest(message string) error { return storeerr.BadRequest(message) }
func conflict(message string) error   { return storeerr.Conflict(message) }
func notFound(message string) error   { return storeerr.NotFound(message) }

// Store owns service-account domain persistence.
type Store struct {
	db coredb.DB
}

// New creates a service-account store.
func New(db coredb.DB) *Store { return &Store{db: db} }

func (store *Store) Validate() error {
	if store == nil || store.db == nil {
		return fmt.Errorf("service account store is not configured")
	}
	return nil
}

// InTx binds service-account persistence to an existing transaction.
func (store *Store) InTx(tx coredb.Tx) *TxStore { return &TxStore{db: tx} }

// TxStore is the transaction-bound service-account repository.
type TxStore struct {
	db coredb.QueryExecer
}

func queryer(store *Store) (coredb.Queryer, error) {
	if store == nil || store.db == nil {
		return nil, fmt.Errorf("service account store database is not configured")
	}
	return store.db, nil
}

func execer(store *Store) (coredb.QueryExecer, error) {
	if store == nil || store.db == nil {
		return nil, fmt.Errorf("service account store database is not configured")
	}
	return store.db, nil
}

func txExecer(store *TxStore) (coredb.QueryExecer, error) {
	if store == nil || store.db == nil {
		return nil, fmt.Errorf("service account tx store database is not configured")
	}
	return store.db, nil
}

func trim(value string) string { return strings.TrimSpace(value) }

func utcOrNow(value time.Time) time.Time {
	if value.IsZero() {
		return time.Now().UTC()
	}
	return value.UTC()
}

func nullableString(value string) any {
	value = trim(value)
	if value == "" {
		return nil
	}
	return value
}

func normalizedName(value string) string { return strings.ToLower(trim(value)) }

func normalizeManagementKind(value string) (string, error) {
	switch value = trim(value); value {
	case ManagementKindWorkspace, ManagementKindPlatform:
		return value, nil
	default:
		return "", badRequest("managementKind must be workspace or platform")
	}
}

func normalizeRequestState(value string) (string, error) {
	switch value = trim(value); value {
	case RequestStateSubmitted,
		RequestStateAwaitingAuthorization,
		RequestStateAuthorized,
		RequestStateDeclined,
		RequestStateCancelled,
		RequestStateProvisioning,
		RequestStateFulfilled,
		RequestStateActionRequired:
		return value, nil
	default:
		return "", badRequest("service account request state is invalid")
	}
}
