"""Built-in documentation viewer.

Usage::

    from sd_api.docs import show_help
    show_help()              # 交互式菜单
    show_help("feature")     # 直接查看功能清单
    show_help("config")      # 直接查看配置清单
    show_help("quickstart")  # 快速开始

文档路径::

    功能清单 CSV : sd_api/docs/功能清单_SD_API_v0.1.0.csv
    配置清单 CSV : sd_api/docs/配置清单_SD_API_v0.1.0.csv
    介绍文档    : sd_api/docs/SD_API_Introduction_v0.1.0.docx
"""

from __future__ import annotations

import csv
import os
import subprocess
import sys
import webbrowser
from pathlib import Path

__all__ = ["show_help", "open_docs", "list_docs", "DOCS_DIR"]

# 包内文档目录（相对于本文件）
_DOCS_DIR = Path(__file__).parent / "docs"
_VERSION = "0.1.0"


def list_docs() -> list[dict]:
    """返回包内所有文档的元信息。"""
    docs = []
    if _DOCS_DIR.exists():
        for f in sorted(_DOCS_DIR.iterdir()):
            if f.is_file():
                size_kb = f.stat().st_size // 1024
                ext = f.suffix.lower()
                docs.append({
                    "name": f.name,
                    "path": str(f.resolve()),
                    "size_kb": size_kb,
                    "type": {
                        ".csv": "表格",
                        ".docx": "Word 文档",
                        ".md": "Markdown",
                        ".pdf": "PDF",
                        ".txt": "文本",
                    }.get(ext, "其他"),
                })
    return docs


def _print_banner():
    width = 60
    print()
    print("╔" + "═" * width + "╗")
    print("║" + " SD-API 文档中心  v" + _VERSION + (" " * (width - 20)) + "║")
    print("╠" + "═" * width + "╣")
    print("║" + "  Python SDK for Real-Time Market Data" + (" " * (width - 43)) + "║")
    print("╚" + "═" * width + "╝")
    print()


def _print_menu():
    docs = list_docs()
    print("  可用文档：")
    if not docs:
        print("  （包内暂无文档，请将文件放入 docs/ 目录）")
    else:
        for i, d in enumerate(docs, 1):
            print(f"  [{i}] {d['name']}  ({d['type']}, {d['size_kb']} KB)")
    print()
    print("  功能说明：")
    print("  [F] 功能清单（全部 79 条功能）")
    print("  [C] 配置清单（全部 13 个配置项）")
    print("  [Q] 快速开始指南")
    print("  [A] API 参考")
    print("  [S] 策略框架示例")
    print("  [T] 测试说明")
    print("  [R] 路由图 / 架构概览")
    print("  [P] PyPI 发布指南")
    print("  [O] 打开文档文件（在系统默认程序中）")
    print("  [X] 退出帮助")
    print()


def _print_csv_as_table(csv_path: Path):
    """将 CSV 文件以格式化表格方式打印到终端。"""
    if not csv_path.exists():
        print(f"  文件不存在：{csv_path}")
        return
    with open(csv_path, newline="", encoding="utf-8-sig") as f:
        reader = csv.reader(f)
        rows = list(reader)
    if not rows:
        print("  文件为空。")
        return
    # 列宽计算
    cols = len(rows[0])
    widths = [max(len(str(r[i]) if i < len(r) else "") for r in rows) + 2 for i in range(cols)]
    total = sum(widths) + cols + 1
    sep = "├" + "┼".join("─" * w for w in widths) + "┤"
    top = "┌" + "┬".join("─" * w for w in widths) + "┐"
    bot = "└" + "┴".join("─" * w for w in widths) + "┘"
    print(top)
    # 表头
    header = rows[0]
    cells = [str(h)[:w].center(w) for h, w in zip(header, widths)]
    print("│" + "│".join(cells) + "│")
    print(sep)
    # 数据行（最多显示 20 行）
    for row in rows[1:21]:
        cells = [str(row[i])[:w].ljust(w) if i < len(row) else "".ljust(w) for i, w in enumerate(widths)]
        print("│" + "│".join(cells) + "│")
    if len(rows) > 21:
        print(f"  ...（共 {len(rows) - 1} 条记录，仅显示前 20 条）")
    print(bot)


def _print_feature_list():
    csv_path = _DOCS_DIR / "功能清单_SD_API_v0.1.0.csv"
    print()
    print("  ═══════════════════════════════════════")
    print("   SD-API 功能清单（全部 79 条）")
    print("  ═══════════════════════════════════════")
    print()
    _print_csv_as_table(csv_path)


def _print_config_list():
    csv_path = _DOCS_DIR / "配置清单_SD_API_v0.1.0.csv"
    print()
    print("  ═══════════════════════════════════════")
    print("   SD-API 配置清单（全部 13 项）")
    print("  ═══════════════════════════════════════")
    print()
    _print_csv_as_table(csv_path)


def _print_quickstart():
    print()
    print("  ═══════════════════════════════════════")
    print("   快速开始指南")
    print("  ═══════════════════════════════════════")
    print()
    lines = [
        ("安装", "pip install sd-api"),
        ("连接", "from sd_api import SDClient\nclient = SDClient('http://127.0.0.1:5000')"),
        ("健康检查", "client.system.health()"),
        ("品种列表", "client.system.products()"),
        ("实时行情", "client.quote.live('XAUUSD')"),
        ("全市场快照", "client.quote.live_all()"),
        ("历史数据", "client.hist.quote_history('XAUUSD', limit=500)"),
        ("K 线", "client.kline.get('XAUUSD', tf='5min', limit=100)"),
        ("SSE 流", "from sd_api import SDStream\nfor q in SDStream('http://127.0.0.1:5000').quote('XAUUSD'): print(q)"),
        ("本地存储", "from sd_api.storage import SQLiteStore\nstore = SQLiteStore('./data/market.db')"),
        ("绘图", "from sd_api.plot import plot_kline\nplot_kline(kline.bars)"),
        ("策略", "from sd_api.strategy import BaseStrategy, StrategyRunner"),
    ]
    for title, code in lines:
        print(f"  ▶ {title}")
        for line in code.split("\n"):
            print(f"    {line}")
        print()


def _print_api_ref():
    print()
    print("  ═══════════════════════════════════════")
    print("   API 参考")
    print("  ═══════════════════════════════════════")
    print()
    apis = [
        ("client.system.health()", "GET /api/health", "HealthStatus"),
        ("client.system.products()", "GET /api/products", "Dict"),
        ("client.quote.live(symbol)", "GET /api/quote-live", "Quote"),
        ("client.quote.latest(symbol)", "GET /api/quote", "Quote"),
        ("client.hist.quote_history(symbol, ...)", "GET /api/quote-hist", "QuoteHistory"),
        ("client.kline.get(symbol, tf='5min')", "GET /api/kline", "KlineSeries"),
        ("stream.quote(symbol)", "SSE", "Generator[Quote]"),
        ("stream.quotes()", "SSE", "Generator[QuoteSnapshot]"),
    ]
    print(f"  {'方法':<40} {'接口':<25} {'返回类型'}")
    print("  " + "─" * 95)
    for method, api, ret in apis:
        print(f"  {method:<40} {api:<25} {ret}")
    print()


def _print_strategy():
    print()
    print("  ═══════════════════════════════════════")
    print("   策略框架示例")
    print("  ═══════════════════════════════════════")
    print()
    code = """\
from sd_api import SDClient, SDStream
from sd_api.strategy import BaseStrategy, StrategyRunner, StrategyContext

class DemoStrategy(BaseStrategy):
    name = "DemoStrategy"

    def on_quote(self, quote: Quote, ctx: StrategyContext) -> None:
        if quote.symbol == "XAUUSD" and quote.latency_ms is not None:
            if quote.latency_ms < 500:
                print(f"[{quote.symbol}] OK: {quote.latency_ms}ms")
            else:
                print(f"[{quote.symbol}] 延迟警告: {quote.latency_ms}ms")

client  = SDClient("http://127.0.0.1:5000")
stream  = SDStream("http://127.0.0.1:5000")
runner  = StrategyRunner(client=client, stream=stream, strategy=DemoStrategy())
runner.run_quote("XAUUSD")  # 持续运行直到 Ctrl+C"""
    for line in code.split("\n"):
        print(f"  {line}")
    print()


def _print_test_info():
    print()
    print("  ═══════════════════════════════════════")
    print("   测试说明")
    print("  ═══════════════════════════════════════")
    print()
    tests = [
        ("tests/test_models.py",   "数据模型单元测试（Quote / KlineBar 等）"),
        ("tests/test_client.py",   "客户端 REST 接口 Mock 测试"),
        ("tests/test_storage.py",  "CSV / SQLite 读写测试"),
        ("tests/test_analysis.py", "分析函数（延迟/点差/信号）测试"),
    ]
    for path, desc in tests:
        print(f"  {path:<25} {desc}")
    print()
    print("  运行测试：")
    print("    pytest tests/ -v")
    print("    pytest tests/test_models.py -v")
    print()


def _print_architecture():
    print()
    print("  ═══════════════════════════════════════")
    print("   SD-API 架构路由图")
    print("  ═══════════════════════════════════════")
    print()
    layers = [
        ("用户代码", ["策略策略 (Strategy)", "业务逻辑 (Strategy / Main)"]),
        ("策略框架 (strategy/)", ["BaseStrategy", "StrategyContext", "StrategyRunner"]),
        ("交易辅助 (trading/)", ["SimulatedExecutor", "OrderRequest", "risk 仓位计算"]),
        ("绘图层 (plot/)", ["plot_kline / plot_spread / plot_latency"]),
        ("分析层 (analysis/)", ["sma / ema / rsi / macd", "latency_summary / spread_stats", "crossover_signal 等"]),
        ("存储层 (storage/)", ["CSVStore", "SQLiteStore", "ParquetStore (可选)"]),
        ("流式层 (stream/)", ["SDStream（统一入口）", "SSEClient / PollerClient", "Dispatcher callback"]),
        ("客户端层 (client/)", ["SDClient ← 6个 Mixin", "health / realtime / history", "kline / products / commands"]),
        ("模型层 (models/)", ["Quote / QuoteSnapshot / QuoteHistory", "KlineBar / KlineSeries", "TradeSignal / OrderFeedback"]),
        ("基础层", ["config / exceptions / logging / version"]),
    ]
    for layer, items in layers:
        print(f"  ▶ {layer}")
        for item in items:
            print(f"    · {item}")
        print()
    print("  数据流向：")
    print("  app-2.py (Flask) → httpx → SDClient → 模型 → 分析/存储/绘图/策略")
    print()


def _print_pypi_guide():
    print()
    print("  ═══════════════════════════════════════")
    print("   PyPI 发布指南")
    print("  ═══════════════════════════════════════")
    print()
    steps = [
        ("① 安装工具", "pip install build twine"),
        ("② 修改版本号（本次发布 0.1.0）", "src/sd_api/version.py → __version__ = '0.1.0'"),
        ("③ 清理旧构建", "rm -rf dist/ build/ *.egg-info/"),
        ("④ 打包", "python -m build"),
        ("⑤ 上传到 PyPI", "twine upload dist/*"),
        ("  PyPI 用户名", "__token__"),
        ("  PyPI 密码", "你的 API Token（PyPI 网站获取）"),
        ("⑥ 验证安装", "pip install sd-api"),
        ("⑦ 确认导入", "python -c 'import sd_api; print(sd_api.__version__)'"),
        ("─ 先发布到 TestPyPI（推荐）─", ""),
        ("⑧ 注册 TestPyPI", "https://test.pypi.org/account/register/"),
        ("⑨ 上传到 TestPyPI", "twine upload --repository testpypi dist/*"),
        ("⑩ 测试安装", "pip install --index-url https://test.pypi.org/simple/ sd-api"),
    ]
    for title, cmd in steps:
        if cmd:
            print(f"  {title}")
            print(f"    $ {cmd}")
        else:
            print(f"  ── {title} ──")
    print()
    print("  上传后 pip install 命令：")
    print("    pip install sd-api          # 基础版")
    print("    pip install sd-api[all]     # 带全部可选依赖")
    print()


def _open_docs_interactive():
    docs = list_docs()
    if not docs:
        print("  暂无文档可打开。")
        return
    print("  请选择要打开的文件（输入编号）：")
    for i, d in enumerate(docs, 1):
        print(f"  [{i}] {d['name']}  ({d['type']})")
    print()
    try:
        choice = input("  输入编号（直接回车取消）: ").strip()
        if not choice:
            return
        idx = int(choice) - 1
        path = docs[idx]["path"]
        print(f"  正在用系统默认程序打开：{path}")
        webbrowser.open(f"file://{path}")
    except (ValueError, IndexError):
        print("  无效选择。")


def show_help(topic: str | None = None) -> None:
    """交互式文档中心。

    Parameters
    ----------
    topic : str | None
        直接指定主题，不显示菜单：
        "feature" / "f" → 功能清单
        "config"  / "c" → 配置清单
        "quickstart" / "q" → 快速开始
        "api" / "a" → API 参考
        "strategy" / "s" → 策略框架
        "test" / "t" → 测试说明
        "arch" / "r" → 架构路由图
        "pypi" / "p" → PyPI 发布指南
        None → 显示交互菜单
    """
    topic = (topic or "").strip().lower()
    _print_banner()

    if topic in ("feature", "f"):
        _print_feature_list()
    elif topic in ("config", "c"):
        _print_config_list()
    elif topic in ("quickstart", "q"):
        _print_quickstart()
    elif topic in ("api", "a"):
        _print_api_ref()
    elif topic in ("strategy", "s"):
        _print_strategy()
    elif topic in ("test", "t"):
        _print_test_info()
    elif topic in ("arch", "r"):
        _print_architecture()
    elif topic in ("pypi", "p"):
        _print_pypi_guide()
    elif topic == "open":
        _open_docs_interactive()
    else:
        while True:
            _print_menu()
            choice = input("  请输入选项（X 退出）: ").strip().lower()
            if choice in ("x", "q", "exit", "quit"):
                print("  再见！")
                break
            elif choice in ("f", "1"):
                _print_feature_list()
            elif choice in ("c", "2"):
                _print_config_list()
            elif choice in ("q", "3"):
                _print_quickstart()
            elif choice in ("a", "4"):
                _print_api_ref()
            elif choice in ("s", "5"):
                _print_strategy()
            elif choice in ("t", "6"):
                _print_test_info()
            elif choice in ("r", "7"):
                _print_architecture()
            elif choice in ("p", "8"):
                _print_pypi_guide()
            elif choice in ("o", "9"):
                _open_docs_interactive()
            else:
                print("  无效选项，请重新输入。")
            input("\n  按回车继续...")


def open_docs():
    """在系统默认程序中打开文档列表。"""
    _print_banner()
    _open_docs_interactive()
