#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import lru_cache
from pathlib import Path
from typing import Literal, Optional, List, Dict, Any
from functools import cached_property
from pydantic import Field, field_validator, computed_field
from pydantic_settings import BaseSettings, SettingsConfigDict


# =================================================================
# 基础配置类
# =================================================================


class DatabaseConfig(BaseSettings):
    """单个数据库配置"""

    enabled: bool = Field(default=False, description="是否启用")
    type: Literal["mysql", "postgresql", "sqlite"] = Field(description="数据库类型")
    host: Optional[str] = Field(default=None)
    port: Optional[int] = Field(default=None)
    database: str = Field(description="数据库名")
    user: Optional[str] = Field(default=None)
    password: Optional[str] = Field(default=None)

    # 连接池
    pool_min_size: int = Field(default=5, ge=1, le=50)
    pool_max_size: int = Field(default=20, ge=1, le=100)
    pool_recycle: int = Field(default=300, ge=60)

    # 超时
    connect_timeout: int = Field(default=10, ge=1)
    command_timeout: int = Field(default=30, ge=1)

    # SSL
    ssl_enabled: bool = Field(default=False)
    ssl_ca: Optional[str] = Field(default=None)
    ssl_cert: Optional[str] = Field(default=None)
    ssl_key: Optional[str] = Field(default=None)

    # 模型
    models: List[str] = Field(default_factory=list, description="模型列表")

    # 数据库特有配置
    charset: str = Field(default="utf8mb4", description="MySQL charset")
    schema: str = Field(default="public", description="PostgreSQL schema")

    echo: bool = Field(default=False, description="打印 SQL")


class Settings(BaseSettings):

    model_config = SettingsConfigDict(
        # 环境变量配置
        env_file=".env",
        env_file_encoding="utf-8",
        env_nested_delimiter="__",
        case_sensitive=False,
        extra="ignore",  # 忽略未定义的环境变量
        validate_default=True,
        validate_assignment=True,
    )

    # =================================================================
    # 环境配置
    # =================================================================

    ENV: Literal["dev", "test", "pro"] = Field(default="dev", description="运行环境")

    @computed_field
    @property
    def is_dev(self) -> bool:
        return self.ENV == "dev"

    @computed_field
    @property
    def is_production(self) -> bool:
        return self.ENV == "pro"

    # =================================================================
    # 应用基础配置
    # =================================================================

    APP_NAME: str = Field(default="Infoman", description="应用名称")
    APP_VERSION: str = Field(default="1.0.0", description="应用版本")
    APP_DESCRIPTION: str = Field(default="Infoman Base Service", description="应用描述")

    # 服务配置
    APP_HOST: str = Field(default="0.0.0.0", description="监听地址")
    APP_PORT: int = Field(default=8008, ge=1, le=65535, description="监听端口")
    APP_BASE_URI: str = Field(default="", description="基础路径")

    # API 文档配置（生产环境自动禁用）
    @computed_field
    @property
    def APP_DOCS_URL(self) -> Optional[str]:
        return "/doc" if not self.is_production else None

    @computed_field
    @property
    def APP_REDOC_URL(self) -> Optional[str]:
        return "/redoc" if not self.is_production else None

    # CORS 配置
    ALLOW_ORIGINS: list[str] = Field(default=["*"], description="允许的来源")
    ALLOW_CREDENTIALS: bool = Field(default=False, description="允许凭证")
    ALLOW_HEADERS: list[str] = Field(
        default=["Content-Type", "Authorization", "X-Request-ID"],
        description="允许的请求头",
    )
    ALLOW_METHODS: list[str] = Field(
        default=["GET", "POST", "PUT", "DELETE", "PATCH"], description="允许的方法"
    )

    # =================================================================
    # 安全配置
    # =================================================================

    JWT_SECRET_KEY: str = Field(
        default="change-me-in-production",
        min_length=32,
        description="JWT 密钥（生产环境必须修改）",
    )
    JWT_ALGORITHM: str = Field(default="HS256", description="JWT 算法")
    JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(
        default=60 * 24,
        ge=1,
        le=43200,  # 最多 30 天
        description="访问令牌过期时间（分钟）",
    )

    OAUTH2_REDIRECT_URL: str = Field(
        default="/auth/callback", description="OAuth2 回调地址"
    )

    # =================================================================
    # MySQL 配置（优化：使用 asyncmy/aiomysql）
    # =================================================================
    # MySQL 主库（默认连接）
    MYSQL_ENABLED: bool = Field(default=False)
    MYSQL_HOST: Optional[str] = Field(default=None)
    MYSQL_PORT: int = Field(default=3306)
    MYSQL_DB: str = Field(default="infoman")
    MYSQL_USER: Optional[str] = Field(default=None)
    MYSQL_PASSWORD: Optional[str] = Field(default=None)
    MYSQL_CHARSET: str = Field(default="utf8mb4")
    MYSQL_POOL_MIN_SIZE: int = Field(default=5)
    MYSQL_POOL_MAX_SIZE: int = Field(default=20)
    MYSQL_MODELS: List[str] = Field(default_factory=list)
    MYSQL_ECHO: bool = Field(default=False)

    # PostgreSQL（分析库）
    POSTGRES_ENABLED: bool = Field(default=False)
    POSTGRES_HOST: Optional[str] = Field(default=None)
    POSTGRES_PORT: int = Field(default=5432)
    POSTGRES_DB: str = Field(default="analytics")
    POSTGRES_USER: Optional[str] = Field(default=None)
    POSTGRES_PASSWORD: Optional[str] = Field(default=None)
    POSTGRES_SCHEMA: str = Field(default="public")
    POSTGRES_POOL_MIN_SIZE: int = Field(default=5)
    POSTGRES_POOL_MAX_SIZE: int = Field(default=20)
    POSTGRES_MODELS: List[str] = Field(default_factory=list)
    POSTGRES_ECHO: bool = Field(default=False)

    # SQLite（本地缓存）
    SQLITE_ENABLED: bool = Field(default=False)
    SQLITE_DB: str = Field(default="cache")
    SQLITE_MODELS: List[str] = Field(default_factory=list)

    # ========== 通用配置 ==========
    DB_TIMEZONE: str = Field(default="Asia/Shanghai")
    DB_USE_TZ: bool = Field(default=False)
    DB_MODELS_PATH: str = Field(default="app.models")

    # ========== 验证器 ==========

    @field_validator("MYSQL_MODELS", "POSTGRES_MODELS", "SQLITE_MODELS", mode="before")
    @classmethod
    def parse_models(cls, v):
        if isinstance(v, str):
            return [m.strip() for m in v.split(",") if m.strip()]
        return v or []

    # ========== MySQL 配置 ==========

    @cached_property
    def mysql_config(self) -> Optional[DatabaseConfig]:
        """MySQL 数据库配置"""
        if not self.MYSQL_ENABLED:
            return None

        if not all([self.MYSQL_HOST, self.MYSQL_USER, self.MYSQL_PASSWORD]):
            return None

        return DatabaseConfig(
            enabled=True,
            type="mysql",
            host=self.MYSQL_HOST,
            port=self.MYSQL_PORT,
            database=self.MYSQL_DB,
            user=self.MYSQL_USER,
            password=self.MYSQL_PASSWORD,
            pool_min_size=self.MYSQL_POOL_MIN_SIZE,
            pool_max_size=self.MYSQL_POOL_MAX_SIZE,
            models=self._get_full_models(self.MYSQL_MODELS),
            charset=self.MYSQL_CHARSET,
            echo=self.MYSQL_ECHO or self.is_dev,
        )

    @cached_property
    def postgres_config(self) -> Optional[DatabaseConfig]:
        if not self.POSTGRES_ENABLED:
            return None

        if not all([self.POSTGRES_HOST, self.POSTGRES_USER, self.POSTGRES_PASSWORD]):
            return None

        return DatabaseConfig(
            enabled=True,
            type="postgresql",
            host=self.POSTGRES_HOST,
            port=self.POSTGRES_PORT,
            database=self.POSTGRES_DB,
            user=self.POSTGRES_USER,
            password=self.POSTGRES_PASSWORD,
            pool_min_size=self.POSTGRES_POOL_MIN_SIZE,
            pool_max_size=self.POSTGRES_POOL_MAX_SIZE,
            models=self._get_full_models(self.POSTGRES_MODELS),
            schema=self.POSTGRES_SCHEMA,
            echo=self.POSTGRES_ECHO or self.is_dev,
        )

    @cached_property
    def sqlite_config(self) -> Optional[DatabaseConfig]:
        if not self.SQLITE_ENABLED:
            return None
        return DatabaseConfig(
            enabled=True,
            type="sqlite",
            database=self.SQLITE_DB,
            models=self._get_full_models(self.SQLITE_MODELS),
        )

    def _get_full_models(self, models: List[str]) -> List[str]:
        """获取完整模型路径"""
        if not models:
            return []
        return [f"{self.DB_MODELS_PATH}.{m}" for m in models]

    @cached_property
    def enabled_databases(self) -> Dict[str, DatabaseConfig]:
        """所有启用的数据库"""
        databases = {}

        if self.mysql_config:
            databases["default"] = self.mysql_config  # MySQL 作为默认连接

        if self.postgres_config:
            databases["postgres"] = self.postgres_config

        if self.sqlite_config:
            databases["sqlite"] = self.sqlite_config

        return databases

    def model_post_init(self, __context):
        # 开发环境自动启用 SQL 日志
        if self.is_dev:
            self.MYSQL_ECHO = True
            self.POSTGRES_ECHO = True

    # =================================================================
    # Redis 配置（优化）⚡
    # =================================================================

    REDIS_HOST: str = Field(default="localhost", description="Redis 主机")
    REDIS_PORT: int = Field(default=6379, ge=1, le=65535, description="Redis 端口")
    REDIS_DB: int = Field(default=0, ge=0, le=15, description="数据库索引")
    REDIS_PASSWORD: Optional[str] = Field(default=None, description="密码")

    # 连接池配置（新增）⚡
    REDIS_POOL_SIZE: int = Field(default=50, ge=1, le=200, description="连接池大小")
    REDIS_POOL_TIMEOUT: int = Field(default=5, ge=1, description="连接超时")
    REDIS_SOCKET_TIMEOUT: int = Field(default=5, ge=1, description="Socket 超时")
    REDIS_SOCKET_CONNECT_TIMEOUT: int = Field(default=5, ge=1, description="连接超时")
    REDIS_SOCKET_KEEPALIVE: bool = Field(default=True, description="保持连接")
    REDIS_RETRY_ON_TIMEOUT: bool = Field(default=True, description="超时重试")
    REDIS_DECODE_RESPONSES: bool = Field(default=True, description="解码响应")

    @computed_field
    @property
    def REDIS_URL(self) -> str:
        """Redis 连接字符串"""
        auth = f":{self.REDIS_PASSWORD}@" if self.REDIS_PASSWORD else ""
        return f"redis://{auth}{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"

    # =================================================================
    # Milvus 配置（优化）
    # =================================================================

    MILVUS_HOST: str = Field(default="localhost", description="Milvus 主机")
    MILVUS_PORT: int = Field(default=19530, ge=1, le=65535, description="端口")
    MILVUS_USER: str = Field(default="", description="用户名")
    MILVUS_PASSWORD: str = Field(default="", description="密码")
    MILVUS_TOKEN: str = Field(default="", description="访问令牌")
    MILVUS_DB_NAME: str = Field(default="default", description="数据库名")
    MILVUS_USE_SECURE: bool = Field(default=False, description="使用 TLS")

    # 连接池配置（优化）⚡
    MILVUS_MAX_CONNECTIONS: int = Field(default=10, ge=1, le=100)
    MILVUS_MAX_IDLE_TIME: int = Field(default=300, ge=60)
    MILVUS_CONNECTION_TTL: int = Field(default=3600, ge=300)
    MILVUS_CONNECTION_TIMEOUT: int = Field(default=30, ge=5)
    MILVUS_HEALTH_CHECK_INTERVAL: int = Field(default=60, ge=10)

    @computed_field
    @property
    def MILVUS_URI(self) -> str:
        """Milvus 连接地址"""
        protocol = "https" if self.MILVUS_USE_SECURE else "http"
        return f"{protocol}://{self.MILVUS_HOST}:{self.MILVUS_PORT}"

    # =================================================================
    # Qdrant 配置（优化）
    # =================================================================

    QDRANT_HOST: Optional[str] = Field(default=None, description="Qdrant 主机")
    QDRANT_API_KEY: Optional[str] = Field(default=None, description="API Key")
    QDRANT_HTTP_PORT: int = Field(default=6333, ge=1, le=65535)
    QDRANT_GRPC_PORT: int = Field(default=6334, ge=1, le=65535)
    QDRANT_PREFER_GRPC: bool = Field(default=True, description="优先使用 gRPC")
    QDRANT_TIMEOUT: int = Field(default=30, ge=5, description="请求超时")

    @computed_field
    @property
    def QDRANT_URL(self) -> Optional[str]:
        """Qdrant 连接地址"""
        if not self.QDRANT_HOST:
            return None
        port = (
            self.QDRANT_GRPC_PORT if self.QDRANT_PREFER_GRPC else self.QDRANT_HTTP_PORT
        )
        return f"{self.QDRANT_HOST}:{port}"

    # =================================================================
    # LLM 配置
    # =================================================================

    LLM_PROXY: str = Field(default="litellm_proxy", description="LLM 代理")
    LLM_TIMEOUT: int = Field(default=60, ge=5, description="LLM 请求超时")
    LLM_MAX_RETRIES: int = Field(default=3, ge=0, le=10, description="最大重试次数")

    # =================================================================
    # NATS 配置
    # =================================================================

    NATS_NAME: Optional[str] = Field(default=None, description="NATS 客户端名称")
    NATS_SERVERS: list[str] = Field(default_factory=list, description="NATS 服务器列表")
    NATS_MAX_RECONNECT_ATTEMPTS: int = Field(
        default=-1, description="重连次数（-1 无限）"
    )
    NATS_RECONNECT_TIME_WAIT: int = Field(default=2, ge=1, description="重连等待时间")

    @field_validator("NATS_SERVERS", mode="before")
    @classmethod
    def parse_nats_servers(cls, v):
        """解析 NATS 服务器列表"""
        if isinstance(v, str):
            return [s.strip() for s in v.split(",") if s.strip()]
        return v or []

    # =================================================================
    # 日志配置（优化）⚡
    # =================================================================

    LOG_LEVEL: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
        default="INFO", description="日志级别"
    )
    LOG_DIR: Path = Field(default=Path("./logs"), description="日志目录")
    LOG_RETENTION: str = Field(default="7 days", description="日志保留时间")
    LOG_ROTATION: str = Field(default="100 MB", description="日志轮转大小")

    # 日志格式
    LOG_FORMAT: Literal["simple", "detailed", "json", "pro"] = Field(
        default="simple", description="日志格式"
    )
    LOG_ENABLE_CONTEXT: bool = Field(default=True, description="启用上下文")
    LOG_ENABLE_JSON: bool = Field(default=False, description="JSON 格式")
    LOG_RECORD_CALLER: bool = Field(default=True, description="记录调用者")
    LOG_ENABLE_COLOR: bool = Field(default=True, description="启用颜色")
    LOG_ENABLE_ASYNC: bool = Field(default=True, description="异步日志")

    @field_validator("LOG_DIR", mode="before")
    @classmethod
    def create_log_dir(cls, v):
        """自动创建日志目录"""
        log_dir = Path(v)
        log_dir.mkdir(parents=True, exist_ok=True)
        return log_dir

    def model_post_init(self, __context):
        """初始化后处理（根据环境调整配置）"""
        if self.ENV == "dev":
            self.LOG_ENABLE_COLOR = True
            self.LOG_FORMAT = "detailed"
            self.LOG_LEVEL = "DEBUG"

        elif self.ENV == "pro":
            self.LOG_ENABLE_COLOR = False
            self.LOG_FORMAT = "json"
            self.LOG_ENABLE_JSON = True

    # =================================================================
    # 国际化配置
    # =================================================================

    DEFAULT_LANGUAGE: Literal["EN", "ZH"] = Field(default="EN", description="默认语言")
    SUPPORTED_LANGUAGES: list[str] = Field(
        default=["EN", "ZH"], description="支持的语言"
    )

    @computed_field
    @property
    def is_english(self) -> bool:
        """是否英文"""
        return self.DEFAULT_LANGUAGE == "EN"


# =================================================================
# 单例模式 + 缓存（性能优化）⚡
# =================================================================


@lru_cache(maxsize=1)
def get_settings() -> Settings:
    """获取配置单例（带缓存）"""
    return Settings()


# 全局配置实例
settings = get_settings()


# =================================================================
# 配置验证（可选）
# =================================================================

<<<<<<< HEAD
=======
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-secret-key-for-jwt")
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
JWT_ACCESS_TOKEN_EXPIRE_MINUTES = int(
    os.getenv("JWT_ACCESS_TOKEN_EXPIRE_MINUTES", "60")
)
>>>>>>> 2139e523a2333d7e8025a6bf69eaae506e297ab7

def validate_config():
    """验证配置（启动时调用）"""
    s = get_settings()

    # 检查生产环境必须修改的配置
    if s.is_production:
        if s.JWT_SECRET_KEY == "change-me-in-production":
            raise ValueError("生产环境必须修改 JWT_SECRET_KEY！")

        if not s.MYSQL_PASSWORD and not s.POSTGRES_PASSWORD:
            raise ValueError("生产环境必须配置数据库密码！")

    print(f"✅ 配置验证通过 [ENV={s.ENV}]")


# =================================================================
# 导出
# =================================================================

<<<<<<< HEAD
__all__ = [
    "Settings",
    "settings",
    "get_settings",
    "validate_config",
]
=======
MYSQL_HOST = os.getenv("MYSQL_HOST", "localhost")
MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306"))
MYSQL_DB = os.getenv("MYSQL_DB", "")
MYSQL_USER = os.getenv("MYSQL_USER", "")
MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "")

MYSQL_TABLE_MODELS_PATH = os.getenv("MYSQL_TABLE_MODELS_PATH", "app.models")
MYSQL_TABLE_MODELS_CONFIG = os.getenv("MYSQL_TABLE_MODELS", "")

MYSQL_TABLE_MODELS = []
if len(MYSQL_TABLE_MODELS_CONFIG) > 0:
    path = MYSQL_TABLE_MODELS_PATH
    MYSQL_TABLE_MODELS = [f"{path}.{m}" for m in MYSQL_TABLE_MODELS_CONFIG.split(",")]

# =================================================================
# Redis
# =================================================================
REDIS_HOST = os.getenv("REDIS_HOST", "localhost")
REDIS_PORT = int(os.getenv("REDIS_PORT", "6379"))
REDIS_DB = int(os.getenv("REDIS_DB", "0"))
REDIS_PASSWORD = os.getenv("REDIS_PASSWORD", None)

# =================================================================
# Milvus
# =================================================================
MILVUS_PREFIX = os.getenv("MILVUS_PREFIX", "http")
MILVUS_HOST = os.getenv("MILVUS_HOST", "")
MILVUS_PORT = int(os.getenv("MILVUS_PORT", 19530))
MILVUS_USER = os.getenv("MILVUS_USER", "")
MILVUS_PASSWD = os.getenv("MILVUS_PASSWD", "")
MILVUS_TOKEN = os.getenv("MILVUS_TOKEN", "")
MILVUS_DB_NAME = os.getenv("MILVUS_DB_NAME", "default")

MILVUS_MAX_IDLE_TIME = int(os.getenv("MILVUS_MAX_IDLE_TIME", 300))
MILVUS_CONNECTION_TTL = int(os.getenv("MILVUS_CONNECTION_TTL", 3600))
MILVUS_MAX_CONNECTIONS = int(os.getenv("MILVUS_MAX_CONNECTIONS", 10))
MILVUS_MIN_CONNECTIONS = int(os.getenv("MILVUS_MIN_CONNECTIONS", 300))
MILVUS_CONNECTION_TIMEOUT = int(os.getenv("MILVUS_CONNECTION_TIMEOUT", 30))
MILVUS_HEALTH_CHECK_INTERVAL = int(os.getenv("MILVUS_HEALTH_CHECK_INTERVAL", 60))

# =================================================================
# Qdrant
# =================================================================
QDRANT_HOST = os.getenv("QDRANT_HOST", None)
QDRANT_API_KEY = os.getenv("QDRANT_API_KEY", None)
QDRANT_HTTP_PORT = int(os.getenv("QDRANT_HTTP_PORT", "6333"))
QDRANT_GRPC_PORT = int(os.getenv("QDRANT_GRPC_PORT", "6334"))
QDRANT_PREFER_GRPC = os.getenv("QDRANT_PREFER_GRPC", "true").lower() == "true"

LLM_PROXY = os.getenv("LLM_PROXY", "litellm_proxy")
# =================================================================
# 国际化配置
# =================================================================

DEFAULT_LANGUAGE = os.getenv("DEFAULT_LANGUAGE", "EN")
DEFAULT_LANGUAGE_IS_EN = DEFAULT_LANGUAGE == "EN"
SUPPORTED_LANGUAGES = ["EN", "ZH"]

# =================================================================
# MQ配置
# =================================================================

NATS_NAME = os.getenv("NATS_NAME", None)
NATS_SERVER = os.getenv("NATS_SERVER", None)
NATS_SERVER_LIST = []
if NATS_SERVER:
    NATS_SERVER_LIST = [m for m in NATS_SERVER.split(",")]

# =================================================================
# 日志配置
# =================================================================

# 日志基础配置
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
LOG_DIR = os.getenv("LOG_DIR", "./logs")
LOG_RETENTION = os.getenv("LOG_RETENTION", "7 days")
LOG_ROTATION = os.getenv("LOG_ROTATION", "100 MB")

# 日志格式与功能配置
LOG_FORMAT = os.getenv("LOG_FORMAT", "simple")  # simple/detailed/debug/pro/json
LOG_ENABLE_CONTEXT = os.getenv("LOG_ENABLE_CONTEXT", "true").lower() == "true"
LOG_ENABLE_JSON_LOGS = os.getenv("LOG_ENABLE_JSON_LOGS", "false").lower() == "true"
LOG_RECORD_CALLER_INFO = os.getenv("LOG_RECORD_CALLER_INFO", "true").lower() == "true"
LOG_ENABLE_CONSOLE_COLOR = (
    os.getenv("LOG_ENABLE_CONSOLE_COLOR", "true").lower() == "true"
)
LOG_ENABLE_ASYNC_LOGGING = (
    os.getenv("LOG_ENABLE_ASYNC_LOGGING", "true").lower() == "true"
)

if env == "dev":
    LOG_ENABLE_CONSOLE_COLOR = True
    LOG_FORMAT = "detailed"

elif env == "test":
    LOG_ENABLE_CONSOLE_COLOR = True
    LOG_FORMAT = "detailed"

elif env == "pro":
    LOG_ENABLE_CONSOLE_COLOR = False
    LOG_FORMAT = "pro"
>>>>>>> 2139e523a2333d7e8025a6bf69eaae506e297ab7
