package store

import (
	"errors"
	"strings"
	"time"
)

var (
	ErrNoModelCandidate                  = errors.New("no enabled platform model matches request")
	ErrRateLimited                       = errors.New("rate limit exceeded")
	ErrInvalidPlatformModelConfiguration = errors.New("invalid platform model configuration")
)

type ModelCandidateUnavailableError struct {
	Code       string
	Message    string
	Details    map[string]any
	RetryAfter time.Duration
	RecoveryAt time.Time
}

func (e *ModelCandidateUnavailableError) Error() string {
	return e.Message
}

func (e *ModelCandidateUnavailableError) Unwrap() error {
	return ErrNoModelCandidate
}

func ModelCandidateErrorCode(err error) string {
	var candidateErr *ModelCandidateUnavailableError
	if errors.As(err, &candidateErr) && strings.TrimSpace(candidateErr.Code) != "" {
		return candidateErr.Code
	}
	return "no_model_candidate"
}

func ModelCandidateErrorDetails(err error) map[string]any {
	var candidateErr *ModelCandidateUnavailableError
	if errors.As(err, &candidateErr) && len(candidateErr.Details) > 0 {
		return candidateErr.Details
	}
	return nil
}

func ModelCandidateRetryAfter(err error) time.Duration {
	var candidateErr *ModelCandidateUnavailableError
	if errors.As(err, &candidateErr) && candidateErr.RetryAfter > 0 {
		return candidateErr.RetryAfter
	}
	return 0
}

func ModelCandidateRecoveryAt(err error) time.Time {
	var candidateErr *ModelCandidateUnavailableError
	if errors.As(err, &candidateErr) {
		return candidateErr.RecoveryAt
	}
	return time.Time{}
}

type RateLimitExceededError struct {
	ScopeType     string
	ScopeKey      string
	ScopeName     string
	ScopeMetadata map[string]any
	Metric        string
	Limit         float64
	Amount        float64
	Current       float64
	Used          float64
	Reserved      float64
	Projected     float64
	WindowSeconds int
	ResetAt       time.Time
	Policy        map[string]any
	Message       string
	RetryAfter    time.Duration
	Retryable     bool
	Reason        string
	QueueDepth    int
	QueueLimit    int
}

func (e *RateLimitExceededError) Error() string {
	if strings.TrimSpace(e.Message) != "" {
		return e.Message
	}
	if strings.TrimSpace(e.Metric) != "" {
		return "rate limit exceeded for " + e.Metric
	}
	return ErrRateLimited.Error()
}

func (e *RateLimitExceededError) ErrorCode() string {
	return "gateway_rate_limited"
}

func (e *RateLimitExceededError) Unwrap() error {
	return ErrRateLimited
}

func RateLimitRetryAfter(err error) time.Duration {
	var limitErr *RateLimitExceededError
	if errors.As(err, &limitErr) && limitErr.RetryAfter > 0 {
		return limitErr.RetryAfter
	}
	return 0
}

func RateLimitRetryable(err error) bool {
	var limitErr *RateLimitExceededError
	if errors.As(err, &limitErr) {
		return limitErr.Retryable
	}
	return errors.Is(err, ErrRateLimited)
}

type CreatePlatformModelInput struct {
	PlatformID            string         `json:"platformId"`
	BaseModelID           string         `json:"baseModelId"`
	CanonicalModelKey     string         `json:"canonicalModelKey"`
	ModelName             string         `json:"modelName"`
	ProviderModelName     string         `json:"providerModelName"`
	ModelAlias            string         `json:"modelAlias"`
	ModelType             StringList     `json:"modelType"`
	DisplayName           string         `json:"displayName"`
	CapabilityOverride    map[string]any `json:"capabilityOverride"`
	Capabilities          map[string]any `json:"capabilities"`
	PricingMode           string         `json:"pricingMode"`
	DiscountFactor        float64        `json:"discountFactor"`
	PricingRuleSetID      string         `json:"pricingRuleSetId"`
	BillingConfigOverride map[string]any `json:"billingConfigOverride"`
	BillingConfig         map[string]any `json:"billingConfig"`
	PermissionConfig      map[string]any `json:"permissionConfig"`
	RetryPolicy           map[string]any `json:"retryPolicy"`
	RateLimitPolicy       map[string]any `json:"rateLimitPolicy"`
	RateLimitPolicyMode   string         `json:"rateLimitPolicyMode" enums:"inherit,override"`
	RuntimePolicySetID    string         `json:"runtimePolicySetId"`
	RuntimePolicyOverride map[string]any `json:"runtimePolicyOverride"`
	Enabled               bool           `json:"enabled"`
}

type RuntimeModelCandidate struct {
	PlatformID               string
	PlatformKey              string
	PlatformName             string
	Provider                 string
	SpecType                 string
	BaseURL                  string
	AuthType                 string
	Credentials              map[string]any
	PlatformConfig           map[string]any
	DefaultPricingMode       string
	DefaultDiscountFactor    float64
	PlatformRetryPolicy      map[string]any
	PlatformRateLimitPolicy  map[string]any
	BaseRateLimitPolicy      map[string]any
	PlatformPriority         int
	PlatformModelID          string
	BaseModelID              string
	CanonicalModelKey        string
	ProviderModelName        string
	ModelName                string
	ModelAlias               string
	ModelType                string
	DisplayName              string
	LegacyAliasUsed          bool
	Capabilities             map[string]any
	CapabilityOverride       map[string]any
	BaseBillingConfig        map[string]any
	BillingConfig            map[string]any
	BillingConfigOverride    map[string]any
	PermissionConfig         map[string]any
	PricingMode              string
	DiscountFactor           float64
	BasePricingRuleSetID     string
	PlatformPricingRuleSetID string
	ModelPricingRuleSetID    string
	ModelRetryPolicy         map[string]any
	ModelRateLimitPolicy     map[string]any
	ModelRateLimitPolicyMode string
	RuntimePolicySetID       string
	RuntimePolicyExplicit    bool
	RuntimePolicyOverride    map[string]any
	RateLimitRuntimeOverride map[string]any
	RuntimeRetryPolicy       map[string]any
	RuntimeRateLimitPolicy   map[string]any
	AutoDisablePolicy        map[string]any
	DegradePolicy            map[string]any
	ClientID                 string
	QueueKey                 string
	LoadRatio                float64
	LoadLimited              bool
	LoadAvoided              bool
	FullReasons              []string
	SelectionReason          string
	LoadMetrics              RuntimeCandidateLoadMetrics
	CacheAffinity            RuntimeCandidateCacheAffinity
	RunningCount             float64
	WaitingCount             float64
	LastAssignedUnix         float64
	ResponseProtocol         string
}

type RuntimeCandidateCacheAffinity struct {
	Key                string
	RequestCount       int
	InputTokens        int
	CachedInputTokens  int
	EMAHitRatio        float64
	LastHitRatio       float64
	LastObservedUnix   float64
	Confidence         float64
	Score              float64
	Boost              float64
	AdjustedPriority   float64
	MatchedPrefixDepth int
	CandidateCount     int
	OverrideReason     string
	Applied            bool
}

type RuntimeCandidateLoadMetrics struct {
	RPMCurrent        float64
	RPMLimit          float64
	RPMRatio          float64
	TPMCurrent        float64
	TPMLimit          float64
	TPMRatio          float64
	ConcurrentCurrent float64
	ConcurrentLimit   float64
	ConcurrentRatio   float64
	SoftCurrent       float64
	SoftRatio         float64
	QueuedCount       float64
	StateRunningCount float64
	StateWaitingCount float64
	StateLimiterRatio float64
}

type RateLimitReservation struct {
	ReservationID   string
	ScopeType       string
	ScopeKey        string
	ScopeName       string
	ScopeMetadata   map[string]any
	Metric          string
	Limit           float64
	Amount          float64
	WindowSeconds   int
	LeaseTTLSeconds int
	WindowStart     time.Time
	Policy          map[string]any
}

type RateLimitResult struct {
	Leases       []ConcurrencyLease
	Reservations []RateLimitReservation
}

type ConcurrencyLease struct {
	ID  string
	TTL time.Duration
}

type CreateTaskAttemptInput struct {
	TaskID             string
	ExecutionToken     string
	AttemptNo          int
	PlatformID         string
	PlatformModelID    string
	ClientID           string
	QueueKey           string
	Status             string
	Simulated          bool
	RequestSnapshot    map[string]any
	Metrics            map[string]any
	PricingSnapshot    map[string]any
	RequestFingerprint string
}

type AsyncTaskQueueItem struct {
	ID        string
	Priority  int
	NextRunAt time.Time
}

type FinishTaskAttemptInput struct {
	AttemptID                string
	Status                   string
	Retryable                bool
	UpstreamSubmissionStatus string
	RequestID                string
	StatusCode               int
	Usage                    map[string]any
	Metrics                  map[string]any
	ResponseSnapshot         map[string]any
	ResponseStartedAt        time.Time
	ResponseFinishedAt       time.Time
	ResponseDurationMS       int64
	ErrorCode                string
	ErrorMessage             string
}

type FinishTaskSuccessInput struct {
	TaskID                string
	ExecutionToken        string
	AttemptID             string
	Result                map[string]any
	Billings              []any
	RequestID             string
	ResolvedModel         string
	Usage                 map[string]any
	Metrics               map[string]any
	BillingSummary        map[string]any
	FinalChargeAmount     float64
	FinalChargeAmountText string
	BillingCurrency       string
	PricingSnapshot       map[string]any
	RequestFingerprint    string
	ResponseStartedAt     time.Time
	ResponseFinishedAt    time.Time
	ResponseDurationMS    int64
	CompletionCallbackURL string
	Simulated             bool
	FinalizeAdmission     bool
}

type FinishTaskManualReviewInput struct {
	TaskID             string
	ExecutionToken     string
	AttemptID          string
	TaskStatus         string
	Code               string
	Message            string
	Result             map[string]any
	RequestID          string
	PricingSnapshot    map[string]any
	RequestFingerprint string
	ResponseStartedAt  time.Time
	ResponseFinishedAt time.Time
	ResponseDurationMS int64
}

type FinishTaskFailureInput struct {
	TaskID                string
	ExecutionToken        string
	Code                  string
	Message               string
	StatusCode            int
	Result                map[string]any
	RequestID             string
	Metrics               map[string]any
	ResponseStartedAt     time.Time
	ResponseFinishedAt    time.Time
	ResponseDurationMS    int64
	CompletionCallbackURL string
	Simulated             bool
	FinalizeAdmission     bool
}

type CreateTaskParamPreprocessingLogInput struct {
	TaskID          string
	AttemptID       string
	AttemptNo       int
	ModelType       string
	PlatformID      string
	PlatformModelID string
	ClientID        string
	Changed         bool
	ChangeCount     int
	ActualInput     map[string]any
	ConvertedOutput map[string]any
	Changes         any
	ModelSnapshot   map[string]any
}
