"""
统一配置存储模块

支持 MySQL 优先、JSON 文件 fallback 的读写策略。
"""
import json
import logging
from pathlib import Path
from typing import Optional

from app.models import AppConfig
from app.storage_manager import get_storage_manager

logger = logging.getLogger(__name__)


def _get_mysql_session_local():
    """动态读取 app.mysql_database.MySQLSessionLocal，避免模块导入顺序问题。"""
    import sys
    module = sys.modules.get("app.mysql_database")
    if module is None:
        return None
    return getattr(module, "MySQLSessionLocal", None)

CONFIG_DIR = Path(__file__).resolve().parent.parent / "config"
CONFIG_FILES = {
    "symbols": CONFIG_DIR / "symbols_config.json",
    "ai": CONFIG_DIR / "ai_config.json",
}

DEFAULT_CONFIGS = {
    "symbols": {"futures": {}, "stock": {}},
    "ai": {
        "models": [],
        "active_model": None,
        "analysis_settings": {
            "enable_technical_analysis": True,
            "enable_fundamental_analysis": False,
            "enable_sentiment_analysis": False,
            "risk_tolerance": "medium",
            "max_position_pct": 10,
        },
    },
}


class ConfigStore:
    """统一配置存储入口。"""

    def __init__(
        self,
        storage_manager=None,
        config_dir: Path = CONFIG_DIR,
        session_maker=None,
    ):
        self.storage_manager = storage_manager or get_storage_manager()
        self.config_dir = config_dir
        self._session_maker_override = session_maker
        self.config_files = {
            "symbols": self.config_dir / "symbols_config.json",
            "ai": self.config_dir / "ai_config.json",
        }

    @property
    def session_maker(self):
        """动态读取 MySQLSessionLocal，避免初始化顺序问题。"""
        if self._session_maker_override is not None:
            return self._session_maker_override
        return _get_mysql_session_local()

    def get_config(self, key: str, fallback: Optional[dict] = None) -> dict:
        """读取配置，优先从 MySQL，其次 JSON 文件。"""
        if key not in self.config_files:
            raise ValueError(f"未知配置键: {key}")

        if self.storage_manager.check_mysql():
            try:
                db_value = self._get_from_mysql(key)
                if db_value is not None:
                    return db_value

                # 数据库未命中：从 JSON 读取并回填
                json_value = self._load_json_from_file(key)
                if json_value is not None:
                    self._save_to_mysql(key, json_value)
                    return json_value
                # JSON 不存在或损坏，使用 fallback 但不回填
                return fallback if fallback is not None else DEFAULT_CONFIGS.get(key, {})
            except Exception as e:
                logger.warning(f"从 MySQL 读取配置 [{key}] 失败，降级到 JSON: {e}")

        json_value = self._load_json_from_file(key)
        if json_value is not None:
            return json_value
        return fallback if fallback is not None else DEFAULT_CONFIGS.get(key, {})

    def set_config(self, key: str, value: dict) -> bool:
        """写入配置，MySQL 可用时先写数据库再写 JSON；MySQL 不可用时只写 JSON。"""
        if key not in self.config_files:
            raise ValueError(f"未知配置键: {key}")

        if self.storage_manager.check_mysql():
            try:
                if not self._save_to_mysql(key, value):
                    logger.warning(f"写入 MySQL 配置 [{key}] 失败，保留 JSON 旧值")
                    return False
            except Exception as e:
                logger.warning(f"写入 MySQL 配置 [{key}] 失败，保留 JSON 旧值: {e}")
                return False

        # MySQL 写入成功或 MySQL 不可用，都更新 JSON fallback
        self._save_to_json(key, value)
        return True

    def _get_from_mysql(self, key: str) -> Optional[dict]:
        """从 MySQL 读取配置。"""
        if self.session_maker is None:
            return None

        with self.session_maker() as db:
            record = db.query(AppConfig).filter(AppConfig.config_key == key).first()
            if record:
                return record.config_value
        return None

    def _save_to_mysql(self, key: str, value: dict) -> bool:
        """保存配置到 MySQL。"""
        if self.session_maker is None:
            return False

        with self.session_maker() as db:
            record = db.query(AppConfig).filter(AppConfig.config_key == key).first()
            if record:
                record.config_value = value
            else:
                record = AppConfig(config_key=key, config_value=value)
                db.add(record)
            db.commit()
        return True

    def _load_json_from_file(self, key: str) -> Optional[dict]:
        """从 JSON 文件读取配置，文件不存在或损坏时返回 None。"""
        file_path = self.config_files[key]
        if file_path.exists():
            try:
                with open(file_path, "r", encoding="utf-8") as f:
                    return json.load(f)
            except Exception as e:
                logger.warning(f"读取 JSON 配置 [{key}] 失败: {e}")
        return None

    def _load_json(self, key: str, fallback: Optional[dict] = None) -> dict:
        """从 JSON 文件读取配置，文件不存在或损坏时返回 fallback。"""
        value = self._load_json_from_file(key)
        if value is not None:
            return value
        return fallback if fallback is not None else DEFAULT_CONFIGS.get(key, {})

    def _save_to_json(self, key: str, value: dict) -> None:
        """保存配置到 JSON 文件（原子写入）。"""
        file_path = self.config_files[key]
        self.config_dir.mkdir(parents=True, exist_ok=True)
        tmp_path = file_path.with_suffix(".tmp")
        try:
            with open(tmp_path, "w", encoding="utf-8") as f:
                json.dump(value, f, ensure_ascii=False, indent=4)
            tmp_path.replace(file_path)
        except Exception:
            if tmp_path.exists():
                tmp_path.unlink()
            raise

    def _config_exists_in_mysql(self, key: str) -> bool:
        """检查 MySQL 中是否已存在配置。"""
        return self._get_from_mysql(key) is not None


_config_store = None


def get_config_store() -> ConfigStore:
    """获取 ConfigStore 单例。"""
    global _config_store
    if _config_store is None:
        _config_store = ConfigStore()
    return _config_store
