"""
應用程式設定模組。

把所有「會因環境而變」的設定值集中在這裡,從環境變數讀取。
好處:
  1. 不會把密鑰寫死在程式碼
  2. 開發 / 測試 / 上線 環境可以用不同設定
  3. 任何模組要拿設定值,都從 `from app.config import settings` 取得,
     不要散落在程式各處 os.environ.get(...)
"""

from functools import lru_cache
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    """應用程式的所有設定值。

    Pydantic 會自動從環境變數讀取對應名稱的值,並做型別驗證。
    例如 `ACCESS_TOKEN_EXPIRE_MINUTES=15` 會被讀成 int 15。
    """

    # ---------- 執行環境 ----------
    ENVIRONMENT: str = Field(default="development", description="development / staging / production")

    # ---------- 資料庫 ----------
    DATABASE_URL: str = Field(
        default="postgresql+asyncpg://coba:coba_dev_password_change_me@localhost:5432/coba",
        description="PostgreSQL 連線字串(async 版,使用 asyncpg driver)",
    )

    # ---------- Redis(階段 1 不直接用,先放著)----------
    REDIS_URL: str = Field(default="redis://localhost:6379/0")

    # ---------- Qdrant 向量庫(階段 3 才用)----------
    QDRANT_URL: str = Field(default="http://localhost:6333")

    # ---------- JWT(登入 Token)----------
    JWT_SECRET_KEY: str = Field(
        default="dev_secret_key_replace_me",
        description="簽 JWT 用的密鑰,上線前必須換成隨機 64 bytes",
    )
    JWT_ALGORITHM: str = Field(default="HS256")
    ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(default=15, description="access token 有效期(分鐘)")
    REFRESH_TOKEN_EXPIRE_DAYS: int = Field(default=7, description="refresh token 有效期(天)")

    # ---------- 第一個 Owner 帳號自動建立 ----------
    SEED_OWNER_EMAIL: str = Field(default="owner@example.com")
    SEED_OWNER_PASSWORD: str = Field(default="ChangeMe123!")
    SEED_OWNER_DISPLAY_NAME: str = Field(default="Owner")

    # ---------- Anthropic Claude API(階段 3 庫柏 AI 用)----------
    # 上線前必須在 .env 裡設定 ANTHROPIC_API_KEY=sk-ant-api03-...
    ANTHROPIC_API_KEY: str = Field(default="", description="Anthropic API key,留空則 AI 功能停用")
    # 三層模型分工:輕量分類 / 一般對話 / 重要分析
    CLAUDE_MODEL_HAIKU: str = Field(default="claude-haiku-4-5")
    CLAUDE_MODEL_SONNET: str = Field(default="claude-sonnet-4-6")
    CLAUDE_MODEL_OPUS: str = Field(default="claude-opus-4-7")

    # ---------- Claude Agent SDK(階段 10:OAuth Max 訂閱)----------
    # `claude setup-token` 產的 long-lived OAuth token(1 年有效)
    # 設了之後 Cooper 主對話走 SDK + 訂閱方案,不再 per-token billing
    CLAUDE_CODE_OAUTH_TOKEN: str = Field(
        default="",
        description="Claude Code OAuth token(走 Max 訂閱方案,5 hour rate limit pool)",
    )
    # 對話走 SDK / 走舊 Anthropic API 的開關 — 預設 SDK 優先,沒 token 才退回舊路
    USE_CLAUDE_SDK: bool = Field(
        default=True,
        description="True=Cooper LINE 對話走 claude_agent_sdk(訂閱);False=用 anthropic API",
    )

    # ---------- LINE Messaging API(階段 6:Cooper 進駐 LINE)----------
    # 從 LINE Developers Console 拿到的三組值。留空則 LINE 整合停用。
    LINE_CHANNEL_ID: str = Field(default="", description="LINE Messaging API Channel ID")
    LINE_CHANNEL_SECRET: str = Field(default="", description="LINE Channel secret(用來驗 webhook 簽章)")
    LINE_CHANNEL_ACCESS_TOKEN: str = Field(
        default="",
        description="LINE Channel access token(長期版,呼叫 reply / push API 用)",
    )
    # LINE 媒體下載暫存路徑(image/audio/file)
    LINE_MEDIA_DIR: str = Field(default="uploads/line", description="LINE 媒體下載落地資料夾")

    # 從 .env 讀(本機開發用,Docker 內會直接用 environment 注入)
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=True,
        extra="ignore",
    )


@lru_cache
def get_settings() -> Settings:
    """取得 Settings 單例。

    用 lru_cache 確保整個應用程式只 new 一次 Settings,
    避免每個請求都重讀環境變數。
    """
    return Settings()


# 對外暴露的設定物件,其他模組直接 `from app.config import settings`
settings = get_settings()
