"""
应用程序配置模块
"""
import datetime
import json
from typing import List, Any, Dict, Type

from pydantic import ValidationError
from pydantic_settings import BaseSettings
from sqlalchemy import insert, update, select

from app.core.constants import API_VERSION, DEFAULT_CREATE_IMAGE_MODEL, DEFAULT_FILTER_MODELS, DEFAULT_MODEL, DEFAULT_STREAM_CHUNK_SIZE, DEFAULT_STREAM_LONG_TEXT_THRESHOLD, DEFAULT_STREAM_MAX_DELAY, DEFAULT_STREAM_MIN_DELAY, DEFAULT_STREAM_SHORT_TEXT_THRESHOLD, DEFAULT_TIMEOUT, MAX_RETRIES
from app.log.logger import get_config_logger
# 延迟导入以避免循环依赖，仅在 sync_initial_settings 中使用
# from app.database.connection import database
# from app.database.models import Settings as SettingsModel
# from app.database.services import get_all_settings # get_all_settings 可能不适合启动时调用，直接查询

logger = get_config_logger()


class Settings(BaseSettings):
    """应用程序配置"""
    # 数据库配置
    MYSQL_HOST: str
    MYSQL_PORT: int
    MYSQL_USER: str
    MYSQL_PASSWORD: str
    MYSQL_DATABASE: str
    
    # API相关配置
    API_KEYS: List[str]
    ALLOWED_TOKENS: List[str]
    BASE_URL: str = f"https://generativelanguage.googleapis.com/{API_VERSION}"
    AUTH_TOKEN: str = ""
    MAX_FAILURES: int = 3
    TEST_MODEL: str = DEFAULT_MODEL
    TIME_OUT: int = DEFAULT_TIMEOUT
    MAX_RETRIES: int = MAX_RETRIES
    
    # 模型相关配置
    SEARCH_MODELS: List[str] = ["gemini-2.0-flash-exp"]
    IMAGE_MODELS: List[str] = ["gemini-2.0-flash-exp"]
    FILTERED_MODELS: List[str] = DEFAULT_FILTER_MODELS
    TOOLS_CODE_EXECUTION_ENABLED: bool = False
    SHOW_SEARCH_LINK: bool = True
    SHOW_THINKING_PROCESS: bool = True
    
    # 图像生成相关配置
    PAID_KEY: str = ""
    CREATE_IMAGE_MODEL: str = DEFAULT_CREATE_IMAGE_MODEL
    UPLOAD_PROVIDER: str = "smms"
    SMMS_SECRET_TOKEN: str = ""
    PICGO_API_KEY: str = ""
    CLOUDFLARE_IMGBED_URL: str = ""
    CLOUDFLARE_IMGBED_AUTH_CODE: str = ""
    
    # 流式输出优化器配置
    STREAM_OPTIMIZER_ENABLED: bool = False
    STREAM_MIN_DELAY: float = DEFAULT_STREAM_MIN_DELAY
    STREAM_MAX_DELAY: float = DEFAULT_STREAM_MAX_DELAY
    STREAM_SHORT_TEXT_THRESHOLD: int = DEFAULT_STREAM_SHORT_TEXT_THRESHOLD
    STREAM_LONG_TEXT_THRESHOLD: int = DEFAULT_STREAM_LONG_TEXT_THRESHOLD
    STREAM_CHUNK_SIZE: int = DEFAULT_STREAM_CHUNK_SIZE

    # 调度器配置
    CHECK_INTERVAL_HOURS: int = 1 # 默认检查间隔为1小时
    TIMEZONE: str = "Asia/Shanghai" # 默认时区

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 设置默认AUTH_TOKEN（如果未提供）
        if not self.AUTH_TOKEN and self.ALLOWED_TOKENS:
            self.AUTH_TOKEN = self.ALLOWED_TOKENS[0]

# 创建全局配置实例
settings = Settings()

def _parse_db_value(key: str, db_value: str, target_type: Type) -> Any:
    """尝试将数据库字符串值解析为目标 Python 类型"""
    try:
        if target_type == List[str]:
            # 尝试解析 JSON 列表，如果失败则按逗号分割
            try:
                parsed = json.loads(db_value)
                if isinstance(parsed, list):
                    return [str(item) for item in parsed]
            except json.JSONDecodeError:
                # 回退到逗号分割，去除空格
                return [item.strip() for item in db_value.split(',') if item.strip()]
            # 如果解析后不是列表或解析失败，返回空列表或进行其他处理
            logger.warning(f"Could not parse '{db_value}' as List[str] for key '{key}', falling back to comma split or empty list.")
            return [item.strip() for item in db_value.split(',') if item.strip()] # Fallback
        elif target_type == bool:
            return db_value.lower() in ('true', '1', 'yes', 'on')
        elif target_type == int:
            return int(db_value)
        elif target_type == float:
            return float(db_value)
        else: # 默认为 str 或其他 pydantic 能处理的类型
            return db_value
    except (ValueError, TypeError, json.JSONDecodeError) as e:
        logger.warning(f"Failed to parse db_value '{db_value}' for key '{key}' as type {target_type}: {e}. Using original string value.")
        return db_value # 解析失败则返回原始字符串

async def sync_initial_settings():
    """
    应用启动时同步配置：
    1. 从数据库加载设置。
    2. 将数据库设置合并到内存 settings (数据库优先)。
    3. 将最终的内存 settings 同步回数据库。
    """
    # 延迟导入以避免循环依赖和确保数据库连接已初始化
    from app.database.connection import database
    from app.database.models import Settings as SettingsModel

    global settings
    logger.info("Starting initial settings synchronization...")

    if not database.is_connected:
        try:
            await database.connect()
            logger.info("Database connection established for initial sync.")
        except Exception as e:
            logger.error(f"Failed to connect to database for initial settings sync: {e}. Skipping sync.")
            return

    try:
        # 1. 从数据库加载设置
        db_settings_raw: List[Dict[str, Any]] = []
        try:
            query = select(SettingsModel.key, SettingsModel.value)
            results = await database.fetch_all(query)
            db_settings_raw = [{"key": row["key"], "value": row["value"]} for row in results]
            logger.info(f"Fetched {len(db_settings_raw)} settings from database.")
        except Exception as e:
            logger.error(f"Failed to fetch settings from database: {e}. Proceeding with environment/dotenv settings.")
            # 即使数据库读取失败，也要继续执行，确保基于 env/dotenv 的配置能同步到数据库

        db_settings_map: Dict[str, str] = {s['key']: s['value'] for s in db_settings_raw}

        # 2. 将数据库设置合并到内存 settings (数据库优先)
        updated_in_memory = False

        for key, db_value in db_settings_map.items():
            if hasattr(settings, key):
                target_type = Settings.__annotations__.get(key)
                if target_type:
                    try:
                        parsed_db_value = _parse_db_value(key, db_value, target_type)
                        memory_value = getattr(settings, key)

                        # 比较解析后的值和内存中的值
                        # 注意：对于列表等复杂类型，直接比较可能不够健壮，但这里简化处理
                        if parsed_db_value != memory_value:
                             # 检查类型是否匹配，以防解析函数返回了不兼容的类型
                            # 优先处理 List[str] 类型，避免直接对泛型使用 isinstance
                            if target_type == List[str]:
                                if isinstance(parsed_db_value, list):
                                    # 可以选择性地添加对列表元素的检查，但这里保持简化
                                    setattr(settings, key, parsed_db_value)
                                    logger.info(f"Updated setting '{key}' in memory from database value (List[str]).")
                                    updated_in_memory = True
                                else:
                                     logger.warning(f"Parsed DB value type mismatch for key '{key}'. Expected List[str], got {type(parsed_db_value)}. Skipping update.")
                            # 对于其他非泛型类型，使用常规的 isinstance 检查
                            elif isinstance(parsed_db_value, target_type):
                                setattr(settings, key, parsed_db_value)
                                logger.info(f"Updated setting '{key}' in memory from database value.")
                                updated_in_memory = True
                            else:
                                logger.warning(f"Parsed DB value type mismatch for key '{key}'. Expected {target_type}, got {type(parsed_db_value)}. Skipping update.")

                    except Exception as e:
                        logger.error(f"Error processing database setting for key '{key}': {e}")
            else:
                 logger.warning(f"Database setting '{key}' not found in Settings model definition. Ignoring.")


        # 如果内存中有更新，重新验证 Pydantic 模型（可选但推荐）
        if updated_in_memory:
            try:
                # 重新加载以确保类型转换和验证
                settings = Settings(**settings.model_dump())
                logger.info("Settings object re-validated after merging database values.")
            except ValidationError as e:
                 logger.error(f"Validation error after merging database settings: {e}. Settings might be inconsistent.")


        # 3. 将最终的内存 settings 同步回数据库
        final_memory_settings = settings.model_dump()
        settings_to_update: List[Dict[str, Any]] = []
        settings_to_insert: List[Dict[str, Any]] = []
        now = datetime.datetime.now(datetime.timezone.utc)

        existing_db_keys = set(db_settings_map.keys())

        for key, value in final_memory_settings.items():
            # 序列化值为字符串或 JSON 字符串
            if isinstance(value, list):
                db_value = json.dumps(value)
            elif isinstance(value, bool):
                db_value = str(value).lower()
            else:
                db_value = str(value)

            data = {
                'key': key,
                'value': db_value,
                'description': f"{key} configuration setting", # 默认描述
                'updated_at': now
            }

            if key in existing_db_keys:
                # 仅当值与数据库中的不同时才更新
                if db_settings_map[key] != db_value:
                    settings_to_update.append(data)
            else:
                # 如果键不在数据库中，则插入
                data['created_at'] = now
                settings_to_insert.append(data)

        # 在事务中执行批量插入和更新
        if settings_to_insert or settings_to_update:
            try:
                async with database.transaction():
                    if settings_to_insert:
                        # 获取现有描述以避免覆盖
                        query_existing = select(SettingsModel.key, SettingsModel.description).where(SettingsModel.key.in_([s['key'] for s in settings_to_insert]))
                        existing_desc = {row['key']: row['description'] for row in await database.fetch_all(query_existing)}
                        for item in settings_to_insert:
                            item['description'] = existing_desc.get(item['key'], item['description'])

                        query_insert = insert(SettingsModel).values(settings_to_insert)
                        await database.execute(query=query_insert)
                        logger.info(f"Synced (inserted) {len(settings_to_insert)} settings to database.")

                    if settings_to_update:
                        # 获取现有描述以避免覆盖
                        query_existing = select(SettingsModel.key, SettingsModel.description).where(SettingsModel.key.in_([s['key'] for s in settings_to_update]))
                        existing_desc = {row['key']: row['description'] for row in await database.fetch_all(query_existing)}

                        for setting_data in settings_to_update:
                            setting_data['description'] = existing_desc.get(setting_data['key'], setting_data['description'])
                            query_update = (
                                update(SettingsModel)
                                .where(SettingsModel.key == setting_data['key'])
                                .values(
                                    value=setting_data['value'],
                                    description=setting_data['description'],
                                    updated_at=setting_data['updated_at']
                                )
                            )
                            await database.execute(query=query_update)
                        logger.info(f"Synced (updated) {len(settings_to_update)} settings to database.")
            except Exception as e:
                logger.error(f"Failed to sync settings to database during startup: {str(e)}")
        else:
            logger.info("No setting changes detected between memory and database during initial sync.")

    except Exception as e:
        logger.error(f"An unexpected error occurred during initial settings sync: {e}")
    finally:
        if database.is_connected:
             try:
                 # Don't disconnect if it's managed elsewhere (e.g., FastAPI lifespan)
                 # await database.disconnect()
                 # logger.info("Database connection closed after initial sync.")
                 pass # Assume connection lifecycle is managed by the application lifespan
             except Exception as e:
                 logger.error(f"Error disconnecting database after initial sync: {e}")

    logger.info("Initial settings synchronization finished.")
