"""数据同步注册表模块。

该模块提供统一的同步任务注册和管理机制，避免在 sync.py 中手动罗列各个接口。

使用方式:
    # 在 api_xxx.py 文件中注册同步任务
    from src.data.sync_registry import sync_registry, SyncTask

    sync_registry.register(
        SyncTask(
            name="pro_bar",
            display_name="Pro Bar 数据",
            description="包含复权因子、换手率、量比的数据",
            sync_func=lambda **kwargs: ProBarSync().sync_all(**kwargs),
            preview_func=lambda **kwargs: ProBarSync().preview_sync(**kwargs),
            order=10,  # 执行顺序
        )
    )

    # 在 sync.py 中统一执行
    from src.data.sync_registry import sync_registry
    results = sync_registry.sync_all(force_full=False, dry_run=False)
"""

from dataclasses import dataclass, field
from typing import Callable, Optional, Any
from collections import OrderedDict

import pandas as pd

from src.data.sync_config import get_rate_limit, get_threads


@dataclass
class SyncTask:
    """同步任务定义。

    Attributes:
        name: 任务唯一标识名
        display_name: 显示名称（用于日志）
        description: 任务描述
        sync_func: 同步函数，接收 force_full, dry_run 等参数
        preview_func: 预览函数（可选）
        order: 执行顺序（数字越小越先执行，默认100）
        enabled: 是否启用（默认True）
    """

    name: str
    display_name: str
    description: str
    sync_func: Callable[..., pd.DataFrame | dict[str, pd.DataFrame]]
    preview_func: Optional[Callable[..., Any]] = None
    order: int = 100
    enabled: bool = True


class SyncRegistry:
    """同步任务注册表。

    统一管理所有数据同步任务，支持自动发现和批量执行。

    Example:
        >>> registry = SyncRegistry()
        >>>
        >>> # 注册类方式同步器
        >>> registry.register_class("daily", DailySync, "日线数据", "股票日线行情", order=10)
        >>>
        >>> # 注册函数方式同步器
        >>> registry.register_func("stock_basic", sync_all_stocks, "股票基本信息", order=5)
        >>>
        >>> # 批量执行所有同步
        >>> results = registry.sync_all()
        >>>
        >>> # 只执行特定任务
        >>> results = registry.sync_selected(["stock_basic", "daily"])
    """

    def __init__(self):
        self._tasks: OrderedDict[str, SyncTask] = OrderedDict()

    def register(self, task: SyncTask) -> "SyncRegistry":
        """注册同步任务。

        Args:
            task: 同步任务定义

        Returns:
            self，支持链式调用
        """
        if task.name in self._tasks:
            print(
                f"[SyncRegistry] Warning: Task '{task.name}' already registered, overwriting"
            )

        self._tasks[task.name] = task
        return self

    def register_class(
        self,
        name: str,
        sync_class: type,
        display_name: str,
        description: str,
        order: int = 100,
    ) -> "SyncRegistry":
        """注册基于类的同步器。

        Args:
            name: 任务名
            sync_class: 同步器类（必须有 sync_all() 和 ensure_table_exists() 方法）
            display_name: 显示名称
            description: 描述
            order: 执行顺序

        Returns:
            self，支持链式调用
        """

        def sync_func(**kwargs) -> dict[str, pd.DataFrame]:
            instance = sync_class()
            instance.ensure_table_exists()
            return instance.sync_all(**kwargs)

        def preview_func(**kwargs) -> Any:
            instance = sync_class()
            return instance.preview_sync(**kwargs)

        return self.register(
            SyncTask(
                name=name,
                display_name=display_name,
                description=description,
                sync_func=sync_func,
                preview_func=preview_func,
                order=order,
            )
        )

    def register_func(
        self,
        name: str,
        sync_func: Callable[..., pd.DataFrame],
        display_name: str,
        description: str = "",
        order: int = 100,
    ) -> "SyncRegistry":
        """注册基于函数的同步器。

        Args:
            name: 任务名
            sync_func: 同步函数
            display_name: 显示名称
            description: 描述
            order: 执行顺序

        Returns:
            self，支持链式调用
        """
        return self.register(
            SyncTask(
                name=name,
                display_name=display_name,
                description=description,
                sync_func=sync_func,
                order=order,
            )
        )

    def get_task(self, name: str) -> Optional[SyncTask]:
        """获取指定任务。

        Args:
            name: 任务名

        Returns:
            SyncTask 或 None
        """
        return self._tasks.get(name)

    def list_tasks(self, enabled_only: bool = True) -> list[SyncTask]:
        """获取所有任务列表（按 order 排序）。

        Args:
            enabled_only: 是否只返回启用的任务

        Returns:
            排序后的任务列表
        """
        tasks = self._tasks.values()
        if enabled_only:
            tasks = [t for t in tasks if t.enabled]
        return sorted(tasks, key=lambda t: t.order)

    def sync_all(
        self,
        force_full: bool = False,
        dry_run: bool = False,
        max_workers: Optional[int] = None,
        selected: Optional[list[str]] = None,
    ) -> dict[str, Any]:
        """执行所有同步任务。

        Args:
            force_full: 是否强制完整重载
            dry_run: 是否仅预览
            max_workers: 工作线程数（传递给支持的任务）
            selected: 只执行指定的任务列表，None表示执行所有

        Returns:
            每个任务的执行结果字典
        """
        tasks = self.list_tasks(enabled_only=True)

        if selected:
            tasks = [t for t in tasks if t.name in selected]

        total = len(tasks)
        results: dict[str, Any] = {}

        print("\n" + "=" * 60)
        print("[SyncRegistry] Starting data synchronization...")
        print(f"[SyncRegistry] Total tasks: {total}")
        print("=" * 60)

        for idx, task in enumerate(tasks, 1):
            # 获取当前接口的配置
            rate_limit = get_rate_limit(task.name)
            threads = get_threads(task.name)

            print(f"\n[{idx}/{total}] Syncing {task.display_name}...")
            print(f"    Rate Limit: {rate_limit}/min, Threads: {threads}")
            if task.description:
                print(f"    Description: {task.description}")

            try:
                # 构建参数
                kwargs: dict[str, Any] = {
                    "force_full": force_full,
                    "dry_run": dry_run,
                }
                if max_workers is not None:
                    kwargs["max_workers"] = max_workers

                # 执行同步
                result = task.sync_func(**kwargs)
                results[task.name] = result

                # 输出统计信息
                if isinstance(result, dict):
                    # 返回 dict[str, DataFrame]，如日线数据
                    total_records = sum(len(df) for df in result.values())
                    print(
                        f"[{idx}/{total}] {task.display_name}: OK ({len(result)} items, {total_records} records)"
                    )
                elif isinstance(result, pd.DataFrame):
                    # 返回 DataFrame
                    print(
                        f"[{idx}/{total}] {task.display_name}: OK ({len(result)} records)"
                    )
                else:
                    print(f"[{idx}/{total}] {task.display_name}: OK")

            except Exception as e:
                print(f"[{idx}/{total}] {task.display_name}: FAILED - {e}")
                results[task.name] = pd.DataFrame()

        # Summary
        print("\n" + "=" * 60)
        print("[SyncRegistry] Sync Summary")
        print("=" * 60)

        success_count = sum(
            1
            for name in results
            if not (isinstance(results[name], pd.DataFrame) and results[name].empty)
        )
        print(
            f"Total tasks: {total}, Success: {success_count}, Failed: {total - success_count}"
        )

        for name, data in results.items():
            task = self._tasks.get(name)
            display_name = task.display_name if task else name

            if isinstance(data, dict):
                total_records = sum(len(df) for df in data.values())
                print(f"  {display_name}: {len(data)} items, {total_records} records")
            elif isinstance(data, pd.DataFrame):
                status = "OK" if not data.empty else "EMPTY/FAILED"
                print(f"  {display_name}: {len(data)} records ({status})")
            else:
                print(f"  {display_name}: Completed")

        print("=" * 60)

        return results

    def preview_all(
        self,
        force_full: bool = False,
        selected: Optional[list[str]] = None,
    ) -> dict[str, Any]:
        """预览所有启用的任务。

        Args:
            force_full: 是否预览完整重载
            selected: 只预览指定的任务列表

        Returns:
            每个任务的预览结果
        """
        tasks = self.list_tasks(enabled_only=True)

        if selected:
            tasks = [t for t in tasks if t.name in selected]

        results: dict[str, Any] = {}

        print("\n" + "=" * 60)
        print("[SyncRegistry] Previewing sync tasks...")
        print("=" * 60)

        for task in tasks:
            if task.preview_func is None:
                print(f"\n[{task.display_name}] Preview not supported")
                continue

            print(f"\n[{task.display_name}] Previewing...")
            try:
                result = task.preview_func(force_full=force_full)
                results[task.name] = result
            except Exception as e:
                print(f"[{task.display_name}] Preview failed: {e}")
                results[task.name] = None

        return results


# Global registry instance
sync_registry = SyncRegistry()
