"""
全局配置中心 —— 从环境变量 / .env 文件加载所有配置项，提供开发环境默认值。
Application settings loaded from environment variables with sensible defaults.
"""

from __future__ import annotations

from pathlib import Path

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    """后端全局配置类，涵盖 ES、Neo4j、Redis、LLM、Embedding 等所有基础设施连接参数及业务开关。

    Central configuration for the zm-rag backend.

    Values are read from environment variables (case-insensitive) or a `.env`
    file located next to this module.  Every field has a default that matches
    the docker-compose development environment.
    """

    # 使用基于 __file__ 的绝对路径定位 .env，避免工作目录不同导致加载失败
    # Use absolute path based on __file__ to locate .env reliably
    model_config = SettingsConfigDict(
        env_file=str(Path(__file__).resolve().parent.parent / ".env"),
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    # ── Application ──────────────────────────────────────────────────────
    app_name: str = "zm-rag"
    app_version: str = "0.1.0"
    debug: bool = False

    # ── Elasticsearch ────────────────────────────────────────────────────
    es_host: str = "http://localhost:9200"
    es_username: str = ""
    es_password: str = ""
    es_chunk_index: str = "gov_doc_chunks"
    es_meta_index: str = "gov_doc_meta"
    es_service_guide_index: str = "gov_service_guides"
    es_request_timeout: int = 30
    # TLS 证书验证开关，生产环境建议设为 True 以防止中间人攻击
    es_verify_certs: bool = False
    # ES 副本数，生产环境建议设为 1 或更高以保证数据高可用
    es_number_of_replicas: int = 0

    # ── Neo4j ────────────────────────────────────────────────────────────
    neo4j_uri: str = "bolt://localhost:7687"
    neo4j_user: str = "neo4j"
    neo4j_password: str = "zm_rag_2024"
    neo4j_database: str = "neo4j"

    # ── Redis ────────────────────────────────────────────────────────────
    redis_url: str = "redis://localhost:6379/0"
    redis_permissions_ttl: int = 300  # seconds

    # ── MySQL ────────────────────────────────────────────────────────────
    mysql_enabled: bool = False
    mysql_host: str = ""
    mysql_port: int = 3306
    mysql_user: str = ""
    mysql_password: str = ""
    mysql_database: str = ""
    mysql_charset: str = "utf8mb4"
    mysql_connect_timeout: int = 5
    mysql_pool_minsize: int = 1
    mysql_pool_maxsize: int = 10

    # ── Research session storage ────────────────────────────────────────
    research_session_backend: str = "mysql"
    research_session_ttl_seconds: int = 604800

    # ── Celery ───────────────────────────────────────────────────────────
    celery_broker_url: str = "redis://localhost:6379/1"
    celery_result_backend: str = "redis://localhost:6379/2"

    # ── LLM (OpenAI-compatible) ──────────────────────────────────────────
    llm_base_url: str = "http://localhost:11434/v1"
    # 生产环境必须配置真实的 API Key，"no-key" 仅用于本地开发（如 Ollama）
    # MUST be configured with a real API key in production; "no-key" is for local dev only (e.g. Ollama)
    llm_api_key: str = "no-key"
    llm_model: str = "qwen2.5:14b"
    llm_temperature: float = 0.3
    llm_max_tokens: int = 4096
    # Set to False to disable chain-of-thought / thinking (e.g. DashScope Qwen)
    llm_enable_thinking: bool = True

    # ── Embedding (OpenAI-compatible) ────────────────────────────────────
    embedding_base_url: str = "http://localhost:11434/v1"
    embedding_api_key: str = "no-key"
    embedding_model: str = "bge-m3:latest"
    embedding_dimensions: int = 1024
    # Max texts per batch for embedding API calls.
    # DashScope text-embedding-v3 limit is 10; set lower to be conservative.
    embedding_batch_size: int = 6

    # ── JWT / Auth ───────────────────────────────────────────────────────
    jwt_secret: str = "zm-rag-dev-secret-change-in-production"
    jwt_algorithm: str = "HS256"

    # Service-to-service token for the Big Lobster KB-compatible adapter.
    # Configure LOBSTER_KB_API_KEY in production; the adapter is unavailable
    # when this value is empty.
    lobster_kb_api_key: str = ""
    lobster_kb_detail_max_chars: int = 40_000

    # ── Data paths ───────────────────────────────────────────────────────
    # Optional service-to-service token for /ingest/webhook/*.
    # When empty, webhook ingest remains unauthenticated for local/dev
    # compatibility. When configured, callers must send:
    # Authorization: Bearer <RAG_INGEST_TOKEN>
    rag_ingest_token: str = ""

    file_storage_path: Path = Path("/data/files")

    @property
    def pdf_storage_path(self) -> Path:
        """Alias for backward compatibility."""
        return self.file_storage_path

    # ── Multi-format document support ─────────────────────────────────
    # 使用 tuple 作为默认值，避免可变默认值在实例间共享导致意外修改
    # Use tuple as default to prevent mutable default sharing across instances
    supported_file_types: tuple[str, ...] = (
        "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx",
        "wps", "et", "ofd", "png", "jpg", "jpeg", "tiff", "bmp",
        "txt", "md", "markdown",
    )
    max_file_size_mb: int = 100

    # Docling
    docling_ocr_enabled: bool = True
    docling_max_tokens: int = 512

    # Java document converter service
    converter_base_url: str = "http://localhost:18800"
    converter_timeout: int = 120

    # Formats that need conversion via Java service before Docling processing
    formats_need_conversion: list[str] = ["doc", "xls", "ppt", "wps", "et", "ofd"]

    # ── Knowledge Graph ───────────────────────────────────────────────────
    # Set to False to skip graph construction during document ingest.
    graph_build_enabled: bool = True
    # Maximum body characters forwarded to the LLM for entity extraction.
    graph_max_content_chars: int = 12_000

    # ── Summary Generation ────────────────────────────────────────────────
    # Set to False to disable automatic summary generation during ingest.
    summary_enabled: bool = True
    # Maximum document characters forwarded to the LLM for summarisation.
    summary_max_content_chars: int = 8_000
    # LLM 摘要生成的最大 token 数 / Max tokens for LLM summary generation
    summary_max_tokens: int = 512

    # ── Document Analysis (unified metadata + summary) ────────────────────
    # 统一文档分析：将元数据提取和摘要生成合并为单次 LLM 调用
    # Max document characters for the unified metadata+summary LLM call.
    analysis_max_content_chars: int = 50_000

    # ── Rate Limiting ─────────────────────────────────────────────────────
    rate_limit_enabled: bool = True
    rate_limit_research_max: int = 10       # max requests per window
    rate_limit_research_window: int = 60    # window in seconds
    rate_limit_search_max: int = 60
    rate_limit_search_window: int = 60
    rate_limit_default_max: int = 200
    rate_limit_default_window: int = 60

    # ── Cache TTLs ────────────────────────────────────────────────────────
    # Set to 0 to disable embedding cache.
    embedding_cache_ttl: int = 3600    # seconds
    search_cache_ttl: int = 120        # seconds (0 = disabled)
    # 检索结果分数阈值，低于此值的结果将被过滤（0 = 不过滤）
    search_score_threshold: float = 0.5

    # ── Ingest Tracing ──────────────────────────────────────────────────
    es_trace_index: str = "gov_doc_ingest_traces"
    es_event_index: str = "gov_doc_ingest_events"
    es_artifact_index: str = "gov_doc_ingest_artifacts"
    # Retention days for cleanup tasks
    trace_retention_days: int = 180
    event_retention_days: int = 90
    artifact_retention_days_standard: int = 30
    artifact_retention_days_debug: int = 7

    # ── CORS ─────────────────────────────────────────────────────────────
    cors_origins: list[str] = ["http://localhost:3000", "http://localhost:5173"]


# Singleton – import this wherever settings are needed.
settings = Settings()
