import os
from typing import Optional

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


class Settings(BaseSettings):
    APP_NAME: str = "xiaoxia-saas"
    APP_VERSION: str = "0.1.61"
    ENVIRONMENT: str = "development"
    DEBUG: bool = True

    # 应用基础 URL，用于生成认证邮件中的链接
    # 开发环境默认 http://localhost:3000
    # 生产环境应通过环境变量 APP_BASE_URL 设置
    APP_BASE_URL: str = "http://localhost:3000"

    # Container bind address; external expose is controlled by Docker/Nginx.
    API_HOST: str = "0.0.0.0"  # nosec: B104
    API_PORT: int = 8000
    API_PREFIX: str = "/api/v1"

    DATABASE_URL: str = "postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas"
    DATABASE_POOL_SIZE: int = 20
    DATABASE_MAX_OVERFLOW: int = 10  # 调整为合理值：pool_size(20) + max_overflow(10) = 最大30连接
    DATABASE_POOL_TIMEOUT: int = 30
    DATABASE_POOL_RECYLE: int = 3600
    USE_IN_MEMORY_DB: bool = False
    AUTO_CREATE_SCHEMA: bool = False

    REDIS_URL: str = "redis://localhost:6379/0"
    REDIS_MAX_CONNECTION: int = 50
    ENABLE_REDIS_SESSIONS: bool = False

    # JWT secret key - MUST be set via environment variable, no default allowed
    JWT_SECRET_KEY: Optional[str] = None
    # 旧的 JWT secret key（用于密钥轮换期间验证旧 token）
    # 在密钥轮换时，先设置新密钥，旧密钥保留在此处直到所有旧 token 过期
    JWT_SECRET_KEY_OLD: Optional[str] = None
    # 密钥轮换天数（到达此天数后建议更换密钥）
    SECRET_ROTATION_DAYS: int = 90

    @field_validator("JWT_SECRET_KEY", mode="before")
    @classmethod
    def validate_jwt_secret_key(cls, v):
        if v is None or v == "":
            raise ValueError(
                "JWT_SECRET_KEY must be set via environment variable. " "Do not use default value in production!"
            )
        # Block known insecure default values
        insecure_defaults = [
            "your-secret-key-change-in-production",
            "your-secret-key",
            "secret",
            "changeme",
            "password",
        ]
        if v.lower() in [d.lower() for d in insecure_defaults]:
            raise ValueError(
                f"JWT_SECRET_KEY '{v}' is insecure. " "Please set a strong random secret via environment variable."
            )
        return v

    ENABLE_EMAIL_DELIVERY: bool = False
    SMTP_HOST: str = "smtp.gmail.com"
    SMTP_PORT: int = 587
    SMTP_USER: str = ""
    SMTP_PASSWORD: str = ""
    SMTP_FROM_EMAIL: str = ""
    SMTP_FROM_NAME: str = "小虾 SaaS"
    SMTP_USE_TLS: bool = True

    CELERY_BROKER_URL: str = "redis://localhost:6379/0"
    CELERY_RESULT_BACKEND: str = "redis://localhost:6379/1"

    # OSS 七牛云相关
    OSS_ENDPOINT: str = "oss-cn-hangzhou.aliiyuncs.com"
    OSS_ACCESS_KEY_ID: str = ""
    OSS_ACCESS_KEY_SECRET: str = ""
    OSS_BUCKET_NAME: str = "xiaoxia-autocut"
    OSS_DIRECT_UPLOAD_MAX_MB: int = Field(
        default=2000,
        validation_alias=AliasChoices("OSS_DIRECT_UPLOAD_MAX_MB", "MAX_UPLOAD_SIZE_MB"),
    )
    OSS_DIRECT_UPLOAD_EXPIRE_SECONDS: int = 900

    LOG_LEVEL: str = "INFO"
    CORS_ORIGINS_RAW: str = "http://localhost:3000,http://localhost:5173,http://localhost:8000"

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

    @property
    def CORS_ORIGINS(self) -> list[str]:
        return [origin.strip() for origin in self.CORS_ORIGINS_RAW.split(",") if origin.strip()]

    @property
    def database_url(self) -> str:
        return self.DATABASE_URL

    @property
    def redis_url(self) -> str:
        return self.REDIS_URL

    @property
    def celery_broker_url(self) -> str:
        return self.CELERY_BROKER_URL

    @property
    def celery_result_backend(self) -> str:
        return self.CELERY_RESULT_BACKEND

    @property
    def oss_endpoint(self) -> str:
        return self.OSS_ENDPOINT

    @property
    def oss_access_key_id(self) -> str:
        return self.OSS_ACCESS_KEY_ID

    @property
    def oss_access_key_secret(self) -> str:
        return self.OSS_ACCESS_KEY_SECRET

    @property
    def oss_bucket_name(self) -> str:
        return self.OSS_BUCKET_NAME


_settings: Optional[Settings] = None


def get_settings() -> Settings:
    global _settings
    if _settings is None:
        env = os.getenv("APP_ENV", "development")
        env_file = f".env.{env}" if env != "development" else ".env"
        if os.path.exists(env_file):
            _settings = Settings(_env_file=env_file)
        else:
            _settings = Settings()
    return _settings


settings = get_settings()
