import os
from typing import Literal, Optional

from pydantic import model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    """应用配置"""
    # 环境标识
    ENV: Literal["dev", "uat", "prod"] = "dev"
    DEBUG: bool = False
    
    # 应用配置
    APP_NAME: str = "FastAPI Demo"
    APP_HOST: str = "0.0.0.0"
    APP_PORT: int = 8000
    
    # 数据库配置
    DB_TYPE: Literal["postgresql", "mysql", "sqlserver"] = "postgresql"  # 数据库类型
    DB_HOST: str = "localhost"
    DB_PORT: int = 5432
    DB_USER: str = "postgres"
    DB_PASSWORD: str = ""
    DB_NAME: str = "fastapi_db"
    
    # 数据库连接URL（可手动配置，否则根据 DB_TYPE 自动拼接）
    DATABASE_URL: Optional[str] = None
    
    # 分页配置
    PAGE_SIZE: int = 20
    PAGE_MAX_SIZE: int = 500
    
    # 时区配置（IANA时区名称，如 Asia/Shanghai, America/New_York, UTC 等）
    TIMEZONE: str = "Asia/Shanghai"
    
    # Redis配置
    REDIS_HOST: str = "localhost"
    REDIS_PORT: int = 6379
    REDIS_PASSWORD: str = ""
    REDIS_DB: int = 0
    REDIS_URL: Optional[str] = None
    
    # 缓存配置
    CACHE_DEFAULT_EXPIRE: int = 300  # 默认缓存过期时间（秒）
    CACHE_PREFIX: str = "fastapi:"  # 缓存key前缀
    
    # JWT配置
    JWT_SECRET_KEY: str = "your-strong-secret-key-change-in-production"  # JWT密钥，生产环境必须修改
    JWT_ALGORITHM: str = "HS256"  # JWT算法
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7  # Access Token过期时间（分钟）
    REFRESH_TOKEN_EXPIRE_DAYS: int = 30  # Refresh Token过期时间（天）
    ALLOW_MULTI_DEVICE_LOGIN: bool = True  # 是否允许多设备同时登录（False=单设备登录，新登录会踢掉旧设备）

    # 文件存储配置
    FILE_STORAGE_TYPE: str = "minio"  # local/oss/minio/azure
    FILE_STORAGE_LOCAL_PATH: Optional[str] = None  # 本地存储路径
    # OSS配置
    OSS_ENDPOINT: Optional[str] = None
    OSS_ACCESS_KEY_ID: Optional[str] = None
    OSS_ACCESS_KEY_SECRET: Optional[str] = None
    OSS_BUCKET_NAME: Optional[str] = None
    # Minio配置
    MINIO_ENDPOINT: Optional[str] = None
    MINIO_ACCESS_KEY: Optional[str] = None
    MINIO_SECRET_KEY: Optional[str] = None
    MINIO_BUCKET_NAME: Optional[str] = None
    MINIO_SECURE: bool = False
    # Azure配置
    AZURE_ACCOUNT_NAME: Optional[str] = None
    AZURE_ACCOUNT_KEY: Optional[str] = None
    AZURE_CONTAINER_NAME: Optional[str] = None

    # OAuth配置
    GRANT_ADMIN_TO_OAUTH_USER: bool = True  # 是否给OAuth用户授予管理员权限
    OAUTH_DEFAULT_DEPT_ID: Optional[str] = 'fbsamU5f2VNtjAJhpGJdy'  # OAuth用户默认部门ID
    # Gitee OAuth
    GITEE_CLIENT_ID: Optional[str] = None
    GITEE_CLIENT_SECRET: Optional[str] = None
    GITEE_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/gitee/callback'
    # GitHub OAuth
    GITHUB_CLIENT_ID: Optional[str] = None
    GITHUB_CLIENT_SECRET: Optional[str] = None
    GITHUB_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/github/callback'
    # QQ OAuth
    QQ_APP_ID: Optional[str] = None
    QQ_APP_KEY: Optional[str] = None
    QQ_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/qq/callback'
    # Google OAuth
    GOOGLE_CLIENT_ID: Optional[str] = None
    GOOGLE_CLIENT_SECRET: Optional[str] = None
    GOOGLE_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/google/callback'
    # 微信 OAuth
    WECHAT_APP_ID: Optional[str] = None
    WECHAT_APP_SECRET: Optional[str] = None
    WECHAT_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/wechat/callback'
    # Microsoft OAuth
    MICROSOFT_CLIENT_ID: Optional[str] = None
    MICROSOFT_CLIENT_SECRET: Optional[str] = None
    MICROSOFT_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/microsoft/callback'
    # 钉钉 OAuth
    DINGTALK_APP_ID: Optional[str] = None
    DINGTALK_APP_SECRET: Optional[str] = None
    DINGTALK_REDIRECT_URI: Optional[str] = 'https://localhost:5777/oauth/dingtalk/callback'
    DINGTALK_H5_REDIRECT_URI: Optional[str] = 'http://localhost:5174/pages/oauth/dingtalk/callback'  # uniapp H5 端回调地址
    # 飞书 OAuth
    FEISHU_APP_ID: Optional[str] = None
    FEISHU_APP_SECRET: Optional[str] = None
    FEISHU_REDIRECT_URI: Optional[str] = 'https://localhost:5777/oauth/feishu/callback'
    FEISHU_H5_REDIRECT_URI: Optional[str] = 'http://localhost:5174/pages/oauth/feishu/callback'  # uniapp H5 端回调地址
    # 企业微信 OAuth
    WECOM_CORP_ID: Optional[str] = None
    WECOM_AGENT_ID: Optional[str] = None
    WECOM_APP_SECRET: Optional[str] = None
    WECOM_REDIRECT_URI: Optional[str] = 'https://localhost:5777/oauth/wecom/callback'
    WECOM_H5_REDIRECT_URI: Optional[str] = 'http://localhost:5174/pages/oauth/wecom/callback'  # uniapp H5 端回调地址

    # SMTP 邮件配置
    SMTP_HOST: Optional[str] = None
    SMTP_PORT: int = 465
    SMTP_USER: Optional[str] = None
    SMTP_PASSWORD: Optional[str] = None
    SMTP_USE_TLS: bool = True
    SMTP_FROM_NAME: Optional[str] = None  # 发件人显示名称，默认使用 APP_NAME
    SMTP_FROM_EMAIL: Optional[str] = None  # 发件人邮箱，默认使用 SMTP_USER

    # 钉钉通知配置
    DINGTALK_WEBHOOK_URL: Optional[str] = None  # 群机器人 Webhook 地址
    DINGTALK_WEBHOOK_SECRET: Optional[str] = None  # 群机器人签名密钥
    DINGTALK_AGENT_ID: Optional[str] = None  # 企业内部应用 AgentId（工作通知需要）
    DINGTALK_CORP_ID: Optional[str] = None  # 企业 CorpId（工作通知需要）
    DINGTALK_TODO_PC_URL: Optional[str] = None  # 钉钉待办 PC 端跳转基础 URL
    DINGTALK_TODO_APP_URL: Optional[str] = None  # 钉钉待办移动端跳转基础 URL

    # 飞书通知配置
    FEISHU_WEBHOOK_URL: Optional[str] = None  # 群机器人 Webhook 地址
    FEISHU_WEBHOOK_SECRET: Optional[str] = None  # 群机器人签名密钥

    # 企业微信通知配置
    WECOM_WEBHOOK_URL: Optional[str] = None  # 群机器人 Webhook 地址

    # 微信公众号模板消息配置（复用 WECHAT_APP_ID / WECHAT_APP_SECRET）
    WECHAT_MP_TEMPLATE_ID: Optional[str] = None  # 模板消息 ID
    WECHAT_MP_URL: Optional[str] = None  # 模板消息点击跳转链接
    WECHAT_MP_MINI_APPID: Optional[str] = None  # 跳转小程序 appid（可选）
    WECHAT_MP_MINI_PAGE: Optional[str] = None  # 跳转小程序页面路径（可选）

    # 短信通知配置
    SMS_PROVIDER: Optional[str] = None  # 短信服务商: aliyun / tencent
    # 阿里云短信
    ALIYUN_SMS_ACCESS_KEY_ID: Optional[str] = None
    ALIYUN_SMS_ACCESS_KEY_SECRET: Optional[str] = None
    ALIYUN_SMS_SIGN_NAME: Optional[str] = None  # 短信签名
    ALIYUN_SMS_TEMPLATE_CODE: Optional[str] = None  # 短信模板编号
    # 腾讯云短信
    TENCENT_SMS_SECRET_ID: Optional[str] = None
    TENCENT_SMS_SECRET_KEY: Optional[str] = None
    TENCENT_SMS_SDK_APP_ID: Optional[str] = None  # 短信应用 SDKAppID
    TENCENT_SMS_SIGN_NAME: Optional[str] = None  # 短信签名
    TENCENT_SMS_TEMPLATE_ID: Optional[str] = None  # 短信模板 ID

    # 系统通知用户（用于聊天通知渠道的发送者）
    SYSTEM_NOTIFY_USER_ID: Optional[str] = None

    # 向量数据库配置（Qdrant）
    VECTOR_STORE_TYPE: str = "qdrant"  # 向量存储类型
    QDRANT_HOST: str = "pro.fuadmin.cn"
    QDRANT_PORT: int = 6333
    QDRANT_GRPC_PORT: int = 6334
    QDRANT_API_KEY: Optional[str] = None
    QDRANT_PREFER_GRPC: bool = False

    # 语音，ocr模型key（优先从数据库 LLMProvider qwen 提供商获取，此处作为兜底）
    DASHSCOPE_API_KEY: Optional[str] = None

    model_config = SettingsConfigDict(
        env_file=f"env/{os.getenv('ENV', 'dev')}.env",
        env_file_encoding="utf-8",
        case_sensitive=True,
        extra="ignore",
    )
    
    @model_validator(mode="after")
    def build_urls(self) -> "Settings":
        """自动拼接DATABASE_URL和REDIS_URL"""
        if not self.DATABASE_URL:
            if self.DB_TYPE == "mysql":
                self.DATABASE_URL = (
                    f"mysql+aiomysql://{self.DB_USER}:{self.DB_PASSWORD}"
                    f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}?charset=utf8mb4"
                )
            elif self.DB_TYPE == "sqlserver":
                self.DATABASE_URL = (
                    f"mssql+aioodbc://{self.DB_USER}:{self.DB_PASSWORD}"
                    f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
                    f"?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes"
                )
            else:
                self.DATABASE_URL = (
                    f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASSWORD}"
                    f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
                )
        if not self.REDIS_URL:
            if self.REDIS_PASSWORD:
                self.REDIS_URL = (
                    f"redis://:{self.REDIS_PASSWORD}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
                )
            else:
                self.REDIS_URL = f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
        return self


def get_settings() -> Settings:
    """根据环境变量加载对应的配置文件"""
    env = os.getenv("ENV", "dev")
    return Settings(_env_file=f"env/{env}.env")


settings = get_settings()
