from __future__ import annotations

import logging
from typing import Optional

from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

logger = logging.getLogger(__name__)


class Settings(BaseSettings):
    """Single source of truth for every runtime value.

    Secrets are mandatory at construction: they have no defaults. The only
    values with defaults are operational tuning knobs (timeouts, concurrency,
    cron parameters, the OG site name). Anything missing at boot surfaces a
    clean ValidationError long before the orchestration ever starts.
    """

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=True,
        extra="ignore",
    )

    # ── App ────────────────────────────────────────────────────────────
    APP_ENV: str = "production"
    APP_HOST: str = "0.0.0.0"
    APP_PORT: int = 8000
    APP_VERSION: str = "12.0.0"
    BRIEF_SERVICE_API_KEYS: str = Field(
        ...,
        description="Comma-separated bearer tokens accepted by POST /api/v1/brief/run",
    )
    APP_TIMEZONE: str = "America/Los_Angeles"
    DAYS_TO_SHOW: int = 7
    SHOW_CONCURRENCY: int = 3

    # ── DB ─────────────────────────────────────────────────────────────
    DATABASE_URL: str = Field(
        ...,
        description="postgresql://user:pass@host:5432/city_briefs_ops",
    )

    # ── Hub DB API (cleaned planner.maxify.it mirror) ──────────────────
    SCC_BASE_URL: str = "https://planner.maxify.it"
    SCC_API_KEY: str = Field(
        ...,
        description="Bearer token for planner.maxify.it /api/* read APIs",
    )

    # ── Perplexity ─────────────────────────────────────────────────────
    PERPLEXITY_API_KEY: str = Field(..., description="Perplexity Sonar API key")
    PERPLEXITY_MODEL: str = "sonar-pro"
    PERPLEXITY_TIMEOUT: int = 60
    PERPLEXITY_MAX_CONCURRENCY: int = 2

    # ── OpenAI (powers BOTH fact-check and 20-idea generation in Phase 12) ──
    OPENAI_API_KEY: str = Field(..., description="OpenAI API key (gpt-4o)")
    OPENAI_FACT_CHECK_MODEL: str = "gpt-4o"
    OPENAI_GENERATION_MODEL: str = "gpt-4o"
    OPENAI_TIMEOUT: int = 60
    OPENAI_MAX_CONCURRENCY: int = 2

    # ── Anthropic (Claude ranking to top 10) ──────────────────────────────
    ANTHROPIC_API_KEY: str = Field(..., description="Anthropic API key (Claude)")
    ANTHROPIC_RANKING_MODEL: str = "claude-sonnet-4-6"
    ANTHROPIC_TIMEOUT: int = 90
    ANTHROPIC_MAX_CONCURRENCY: int = 2

    # ── YouTube (recent uploads + transcripts to ground ideas in Max's
    #    most recent material — avoids the 20 ideas repeating recent bits) ──
    YOUTUBE_API_KEY: str = Field(..., description="YouTube Data API v3 key")
    YOUTUBE_CHANNEL_ID: str = "UCQTmZczX5kGRgaPIgpy6CyQ"  # Max Amini
    YOUTUBE_MAX_VIDEOS: int = 5
    YOUTUBE_TIMEOUT: int = 30
    YOUTUBE_MAX_CONCURRENCY: int = 2

    # ── Voice ──────────────────────────────────────────────────────────
    VOICE_PROFILES_DIR: str = "./voice_profiles"
    DEFAULT_COMEDIAN_ID: str = "max-amini"

    # ── Publishing ─────────────────────────────────────────────────────
    PUBLIC_BASE_URL: str = "https://just2done.com/brief"
    # Local mode verifies through the Docker web service while keeping the
    # browser-facing canonical URL in PUBLIC_BASE_URL.
    INTERNAL_PUBLIC_BASE_URL: str = ""
    BRIEF_OUTPUT_DIR: str = "/brief-output"
    OG_COVER_URL: str = "https://just2done.com/brief/og-cover.jpg"
    INTERNAL_OG_COVER_URL: str = ""
    OG_SITE_NAME: str = "Max Amini"

    # ── Slack (informational; notifications go through n8n) ─────────────
    SLACK_ALERTS_CHANNEL: str = "#city-brief-alerts"

    # ── Derived helpers ────────────────────────────────────────────────
    @field_validator("BRIEF_SERVICE_API_KEYS")
    @classmethod
    def _strip_keys(cls, v: str) -> str:
        return ",".join(s.strip() for s in v.split(",") if s.strip())

    @property
    def accepted_api_keys(self) -> set[str]:
        return {s for s in self.BRIEF_SERVICE_API_KEYS.split(",") if s}

    @property
    def credentials_summary(self) -> dict[str, str]:
        """Names only — never values. Safe to log."""
        return {
            "scc_api_key": "<set>" if self.SCC_API_KEY else "<unset>",
            "perplexity_api_key": "<set>" if self.PERPLEXITY_API_KEY else "<unset>",
            "openai_api_key": "<set>" if self.OPENAI_API_KEY else "<unset>",
            "anthropic_api_key": "<set>" if self.ANTHROPIC_API_KEY else "<unset>",
            "youtube_api_key": "<set>" if self.YOUTUBE_API_KEY else "<unset>",
            "brief_service_api_keys": "<set>" if self.accepted_api_keys else "<unset>",
        }


settings = Settings()
logger.info("settings loaded: %s", settings.credentials_summary)
