package config

import "time"

const (
	DefaultConfigPath = "./configs/dev.yaml"
	DefaultSource     = "mcp"
)

type Config struct {
	Version       int                 `yaml:"version"`
	Server        ServerConfig        `yaml:"server"`
	MCP           MCPConfig           `yaml:"mcp"`
	Auth          AuthConfig          `yaml:"auth"`
	Database      DatabaseConfig      `yaml:"database"`
	AI            AIConfig            `yaml:"ai"`
	Capture       CaptureConfig       `yaml:"capture"`
	Search        SearchConfig        `yaml:"search"`
	Logging       LoggingConfig       `yaml:"logging"`
	Observability ObservabilityConfig `yaml:"observability"`
	Backfill      BackfillConfig      `yaml:"backfill"`
	MetadataRetry MetadataRetryConfig `yaml:"metadata_retry"`
}

type ServerConfig struct {
	Host           string        `yaml:"host"`
	Port           int           `yaml:"port"`
	ReadTimeout    time.Duration `yaml:"read_timeout"`
	WriteTimeout   time.Duration `yaml:"write_timeout"`
	IdleTimeout    time.Duration `yaml:"idle_timeout"`
	AllowedOrigins []string      `yaml:"allowed_origins"`
}

type MCPConfig struct {
	Path           string        `yaml:"path"`
	SSEPath        string        `yaml:"sse_path"`
	ServerName     string        `yaml:"server_name"`
	Version        string        `yaml:"version"`
	Transport      string        `yaml:"transport"`
	SessionTimeout time.Duration `yaml:"session_timeout"`
	PublicURL      string        `yaml:"public_url"`
	Instructions   string        `yaml:"-"`
}

type AuthConfig struct {
	HeaderName      string      `yaml:"header_name"`
	QueryParam      string      `yaml:"query_param"`
	AllowQueryParam bool        `yaml:"allow_query_param"`
	Keys            []APIKey    `yaml:"keys"`
	OAuth           OAuthConfig `yaml:"oauth"`
}

type APIKey struct {
	ID          string `yaml:"id"`
	Value       string `yaml:"value"`
	Description string `yaml:"description"`
}

type OAuthConfig struct {
	Clients []OAuthClient `yaml:"clients"`
}

type OAuthClient struct {
	ID           string `yaml:"id"`
	ClientID     string `yaml:"client_id"`
	ClientSecret string `yaml:"client_secret"`
	Description  string `yaml:"description"`
}

type DatabaseConfig struct {
	URL             string        `yaml:"url"`
	MaxConns        int32         `yaml:"max_conns"`
	MinConns        int32         `yaml:"min_conns"`
	MaxConnLifetime time.Duration `yaml:"max_conn_lifetime"`
	MaxConnIdleTime time.Duration `yaml:"max_conn_idle_time"`
}

// AIConfig (v2): named providers + per-role chains.
type AIConfig struct {
	Providers  map[string]ProviderConfig `yaml:"providers"`
	Embeddings EmbeddingsRoleConfig      `yaml:"embeddings"`
	Metadata   MetadataRoleConfig        `yaml:"metadata"`
	Background *BackgroundRolesConfig    `yaml:"background,omitempty"`
}

type ProviderConfig struct {
	Type           string            `yaml:"type"`
	BaseURL        string            `yaml:"base_url"`
	APIKey         string            `yaml:"api_key"`
	RequestHeaders map[string]string `yaml:"request_headers,omitempty"`
	AppName        string            `yaml:"app_name,omitempty"`
	SiteURL        string            `yaml:"site_url,omitempty"`
}

type RoleTarget struct {
	Provider string `yaml:"provider"`
	Model    string `yaml:"model"`
}

type RoleChain struct {
	Primary   RoleTarget   `yaml:"primary"`
	Fallbacks []RoleTarget `yaml:"fallbacks,omitempty"`
}

type EmbeddingsRoleConfig struct {
	Dimensions int          `yaml:"dimensions"`
	Primary    RoleTarget   `yaml:"primary"`
	Fallbacks  []RoleTarget `yaml:"fallbacks,omitempty"`
}

type MetadataRoleConfig struct {
	Temperature      float64       `yaml:"temperature"`
	LogConversations bool          `yaml:"log_conversations"`
	Timeout          time.Duration `yaml:"timeout"`
	Primary          RoleTarget    `yaml:"primary"`
	Fallbacks        []RoleTarget  `yaml:"fallbacks,omitempty"`
}

// BackgroundRolesConfig overrides the foreground chains for background workers
// (backfill_embeddings, metadata_retry, reparse_metadata). Either field may be
// nil to inherit the foreground role unchanged.
type BackgroundRolesConfig struct {
	Embeddings *RoleChain `yaml:"embeddings,omitempty"`
	Metadata   *RoleChain `yaml:"metadata,omitempty"`
}

// Chain returns primary followed by fallbacks (deduped, blanks dropped).
func (e EmbeddingsRoleConfig) Chain() []RoleTarget {
	return dedupeTargets(append([]RoleTarget{e.Primary}, e.Fallbacks...))
}

func (m MetadataRoleConfig) Chain() []RoleTarget {
	return dedupeTargets(append([]RoleTarget{m.Primary}, m.Fallbacks...))
}

func (c RoleChain) AsTargets() []RoleTarget {
	return dedupeTargets(append([]RoleTarget{c.Primary}, c.Fallbacks...))
}

func dedupeTargets(in []RoleTarget) []RoleTarget {
	out := make([]RoleTarget, 0, len(in))
	seen := make(map[RoleTarget]struct{}, len(in))
	for _, t := range in {
		if t.Provider == "" || t.Model == "" {
			continue
		}
		if _, ok := seen[t]; ok {
			continue
		}
		seen[t] = struct{}{}
		out = append(out, t)
	}
	return out
}

type CaptureConfig struct {
	Source           string                 `yaml:"source"`
	MetadataDefaults CaptureMetadataDefault `yaml:"metadata_defaults"`
}

type CaptureMetadataDefault struct {
	Type          string `yaml:"type"`
	TopicFallback string `yaml:"topic_fallback"`
}

type SearchConfig struct {
	DefaultLimit     int     `yaml:"default_limit"`
	DefaultThreshold float64 `yaml:"default_threshold"`
	MaxLimit         int     `yaml:"max_limit"`
}

type LoggingConfig struct {
	Level  string `yaml:"level"`
	Format string `yaml:"format"`
}

type ObservabilityConfig struct {
	MetricsEnabled bool `yaml:"metrics_enabled"`
	PprofEnabled   bool `yaml:"pprof_enabled"`
}

type BackfillConfig struct {
	Enabled         bool          `yaml:"enabled"`
	RunOnStartup    bool          `yaml:"run_on_startup"`
	Interval        time.Duration `yaml:"interval"`
	BatchSize       int           `yaml:"batch_size"`
	MaxPerRun       int           `yaml:"max_per_run"`
	IncludeArchived bool          `yaml:"include_archived"`
}

type MetadataRetryConfig struct {
	Enabled         bool          `yaml:"enabled"`
	RunOnStartup    bool          `yaml:"run_on_startup"`
	Interval        time.Duration `yaml:"interval"`
	MaxPerRun       int           `yaml:"max_per_run"`
	IncludeArchived bool          `yaml:"include_archived"`
}
