#!/usr/bin/env python3
"""
模拟数据存储层

使用 JSON 文件作为本地数据库，方便开发调试。
后续可替换为真实数据库（如 SQLite、MySQL、PostgreSQL）。
"""

import json
import os
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
from threading import Lock

# 数据存储路径
DATA_DIR = Path(__file__).parent / "data"
DATA_DIR.mkdir(exist_ok=True)

# 数据文件
SUBSCRIPTIONS_FILE = DATA_DIR / "subscriptions.json"
STATION_CACHE_FILE = DATA_DIR / "station_cache.json"
STATE_CACHE_FILE = DATA_DIR / "state_cache.json"

# 线程锁
_lock = Lock()


class MockDB:
    """模拟数据库"""

    @staticmethod
    def _load_json(file_path: Path, default: Any = None) -> Any:
        """加载 JSON 文件"""
        if not file_path.exists():
            return default if default is not None else {}
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except (json.JSONDecodeError, FileNotFoundError):
            return default if default is not None else {}

    @staticmethod
    def _save_json(file_path: Path, data: Any) -> bool:
        """保存 JSON 文件"""
        try:
            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(data, f, ensure_ascii=False, indent=2, default=str)
            return True
        except Exception as e:
            print(f"[MockDB] 保存失败: {e}")
            return False

    # ==================== 订阅管理 ====================

    @classmethod
    def get_subscriptions(cls) -> Dict[str, dict]:
        """获取所有订阅"""
        return cls._load_json(SUBSCRIPTIONS_FILE, {})

    @classmethod
    def save_subscriptions(cls, subscriptions: Dict[str, dict]) -> bool:
        """保存所有订阅"""
        with _lock:
            return cls._save_json(SUBSCRIPTIONS_FILE, subscriptions)

    @classmethod
    def add_subscription(cls, email: str) -> bool:
        """添加订阅"""
        with _lock:
            subscriptions = cls.get_subscriptions()
            subscriptions[email.lower()] = {
                "email": email.lower(),
                "created_at": datetime.now().isoformat(),
                "triggered_at": None,
                "expired": False
            }
            return cls._save_json(SUBSCRIPTIONS_FILE, subscriptions)

    @classmethod
    def remove_subscription(cls, email: str) -> bool:
        """移除订阅"""
        with _lock:
            subscriptions = cls.get_subscriptions()
            if email.lower() in subscriptions:
                del subscriptions[email.lower()]
                return cls._save_json(SUBSCRIPTIONS_FILE, subscriptions)
            return True

    @classmethod
    def get_active_subscriptions(cls) -> List[dict]:
        """获取有效订阅列表"""
        subscriptions = cls.get_subscriptions()
        return [
            {"email": email, **data}
            for email, data in subscriptions.items()
            if not data.get("expired", False)
        ]

    @classmethod
    def mark_triggered(cls, email: str) -> bool:
        """标记订阅已触发"""
        with _lock:
            subscriptions = cls.get_subscriptions()
            if email.lower() in subscriptions:
                subscriptions[email.lower()]["triggered_at"] = datetime.now().isoformat()
                return cls._save_json(SUBSCRIPTIONS_FILE, subscriptions)
            return False

    @classmethod
    def mark_expired(cls, email: str) -> bool:
        """标记订阅已过期"""
        with _lock:
            subscriptions = cls.get_subscriptions()
            if email.lower() in subscriptions:
                subscriptions[email.lower()]["expired"] = True
                return cls._save_json(SUBSCRIPTIONS_FILE, subscriptions)
            return False

    # ==================== 充电站缓存 ====================

    @classmethod
    def get_station_cache(cls, station_id: str) -> Optional[dict]:
        """获取充电站缓存"""
        caches = cls._load_json(STATION_CACHE_FILE, {})
        return caches.get(station_id)

    @classmethod
    def save_station_cache(cls, station_id: str, data: dict) -> bool:
        """保存充电站缓存"""
        with _lock:
            caches = cls._load_json(STATION_CACHE_FILE, {})
            caches[station_id] = {
                **data,
                "cached_at": datetime.now().isoformat()
            }
            return cls._save_json(STATION_CACHE_FILE, caches)

    # ==================== 状态缓存（空闲计时） ====================

    @classmethod
    def get_free_state_cache(cls) -> Dict[str, float]:
        """获取空闲状态缓存"""
        return cls._load_json(STATE_CACHE_FILE, {})

    @classmethod
    def save_free_state_cache(cls, cache: Dict[str, float]) -> bool:
        """保存空闲状态缓存"""
        with _lock:
            return cls._save_json(STATE_CACHE_FILE, cache)

    @classmethod
    def update_free_state(cls, connectors: List[dict]) -> Dict[str, float]:
        """更新空闲状态并返回缓存"""
        import time
        with _lock:
            cache = cls.get_free_state_cache()
            now = time.time()

            current_free = set()
            for c in connectors:
                state_type = c.get("state", {}).get("type", "")
                if state_type == "free":
                    key = c.get("connector_id") or c.get("connector_name")
                    if key not in cache:
                        cache[key] = now
                    current_free.add(key)

            # 移除已非空闲的
            for key in list(cache.keys()):
                if key not in current_free:
                    del cache[key]

            cls._save_json(STATE_CACHE_FILE, cache)
            return cache

    # ==================== 工具方法 ====================

    @classmethod
    def clear_all(cls):
        """清空所有数据"""
        for file in [SUBSCRIPTIONS_FILE, STATION_CACHE_FILE, STATE_CACHE_FILE]:
            if file.exists():
                file.unlink()

    @classmethod
    def init_sample_data(cls):
        """初始化示例数据"""
        # 示例订阅
        cls.add_subscription("demo@example.com")
        print("[MockDB] 已添加示例订阅: demo@example.com")


# 命令行工具
if __name__ == "__main__":
    import sys

    print("MockDB 数据管理工具")
    print("=" * 40)

    if len(sys.argv) > 1:
        cmd = sys.argv[1]

        if cmd == "subscriptions":
            subs = MockDB.get_subscriptions()
            print(f"订阅列表 ({len(subs)} 条):")
            for email, data in subs.items():
                print(f"  - {email}: {data}")

        elif cmd == "cache":
            cache = MockDB.get_free_state_cache()
            print(f"空闲缓存 ({len(cache)} 条):")
            for key, ts in cache.items():
                print(f"  - {key}: {datetime.fromtimestamp(ts).isoformat()}")

        elif cmd == "clear":
            MockDB.clear_all()
            print("已清空所有数据")

        elif cmd == "init":
            MockDB.init_sample_data()
            print("已初始化示例数据")

        else:
            print(f"未知命令: {cmd}")
            print("可用命令: subscriptions, cache, clear, init")
    else:
        print("用法: python mock_db.py <command>")
        print("命令:")
        print("  subscriptions  - 查看订阅列表")
        print("  cache          - 查看空闲缓存")
        print("  clear          - 清空所有数据")
        print("  init           - 初始化示例数据")
