// Package routing implements the intelligent routing engine for the Veylant proxy.
// Rules are stored in PostgreSQL (JSONB conditions), cached in-memory (30s TTL),
// and evaluated in priority order (ASC, first match wins).
package routing

import "time"

// ─── Sensitivity ─────────────────────────────────────────────────────────────

// Sensitivity represents the PII risk level of a request, from None to Critical.
// Values are comparable with < / > operators (higher = more sensitive).
type Sensitivity int

const (
	SensitivityNone     Sensitivity = 0
	SensitivityLow      Sensitivity = 1
	SensitivityMedium   Sensitivity = 2
	SensitivityHigh     Sensitivity = 3
	SensitivityCritical Sensitivity = 4
)

// String returns the canonical lowercase name for the sensitivity level.
func (s Sensitivity) String() string {
	switch s {
	case SensitivityNone:
		return "none"
	case SensitivityLow:
		return "low"
	case SensitivityMedium:
		return "medium"
	case SensitivityHigh:
		return "high"
	case SensitivityCritical:
		return "critical"
	default:
		return "unknown"
	}
}

// ParseSensitivity converts a string (none/low/medium/high/critical) to a Sensitivity.
func ParseSensitivity(s string) (Sensitivity, bool) {
	switch s {
	case "none":
		return SensitivityNone, true
	case "low":
		return SensitivityLow, true
	case "medium":
		return SensitivityMedium, true
	case "high":
		return SensitivityHigh, true
	case "critical":
		return SensitivityCritical, true
	default:
		return SensitivityNone, false
	}
}

// ─── Condition ───────────────────────────────────────────────────────────────

// Condition is a single predicate in a routing rule.
// All conditions within a rule must match (AND logic).
type Condition struct {
	// Field identifies the request attribute to test.
	// Supported values: user.role, user.department, request.sensitivity,
	//                   request.model, request.use_case, request.token_estimate
	Field string `json:"field"`

	// Operator specifies how to compare the field value.
	// Supported values: eq, neq, in, nin, gte, lte, contains, matches
	Operator string `json:"operator"`

	// Value is the operand. Type depends on the operator:
	//   eq/neq/contains/matches/gte/lte → string or number
	//   in/nin                          → []interface{} (JSON array of strings)
	Value interface{} `json:"value"`
}

// ─── Action ──────────────────────────────────────────────────────────────────

// Action is the routing decision returned when a rule matches.
type Action struct {
	// Provider is the name of the primary upstream adapter to use.
	// Valid values: openai, anthropic, azure, mistral, ollama
	Provider string `json:"provider"`

	// Model overrides the model name sent to the upstream.
	// If empty, the model from the original ChatRequest is forwarded as-is.
	Model string `json:"model,omitempty"`

	// FallbackProviders are tried in order when the primary provider fails.
	FallbackProviders []string `json:"fallback_providers,omitempty"`
}

// ─── RoutingRule ─────────────────────────────────────────────────────────────

// RoutingRule is a single DB-backed policy entry.
type RoutingRule struct {
	ID          string
	TenantID    string
	Name        string
	Description string
	Conditions  []Condition // ALL must match (AND). Empty slice = catch-all (matches everything).
	Action      Action
	Priority    int  // lower value = evaluated first
	IsEnabled   bool
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

// ─── RoutingContext ───────────────────────────────────────────────────────────

// RoutingContext carries the per-request attributes used by condition evaluation.
type RoutingContext struct {
	TenantID      string
	UserRole      string      // primary role from JWT (e.g. "admin", "user")
	Department    string      // user department from JWT claim
	Sensitivity   Sensitivity // scored from PII detection results
	Model         string      // model name from the ChatRequest
	UseCase       string      // optional use-case tag (e.g. "summarization")
	TokenEstimate int         // estimated prompt token count
}
