"""
固定步长滚动截图辅助工具（v3 — 纯参数计算 + 文件管理）。

本脚本不执行截图或对比，仅提供：
  1. scrollTop 序列计算（给定 scrollHeight → 步数和序列）
  2. 文件命名和目录结构管理
  3. 差异率汇总报告生成

实际截图和对比通过 MCP 工具在对话中执行：
  - H5 截图：Playwright MCP（browser_navigate → browser_evaluate → browser_take_screenshot）
  - MP 截图：微信 MCP（navigate_to → evaluate_script → screenshot）
  - 像素对比：image_compare MCP（compare_images）

用法：
  python scripts/ops/anchor_compare.py calc <scrollHeight>     # 计算 scrollTop 序列
  python scripts/ops/anchor_compare.py status [<page>]         # 查看截图状态
  python scripts/ops/anchor_compare.py report <page>           # 生成/更新差异率报告
  python scripts/ops/anchor_compare.py list                    # 列出所有页面及状态

截图参数（双端统一）：
  viewport 430×752, DPR=1.5, 输出 645×1128
  步长 600px, maxScroll ≤ 10 视为单屏
"""

import io
import json
import math
import sys
from pathlib import Path


def _ensure_utf8_stdio():
    """Windows 终端 GBK 编码兼容：强制 stdout/stderr 为 UTF-8。"""
    if sys.platform == "win32":
        sys.stdout = io.TextIOWrapper(
            sys.stdout.buffer, encoding="utf-8", errors="replace"
        )
        sys.stderr = io.TextIOWrapper(
            sys.stderr.buffer, encoding="utf-8", errors="replace"
        )


# ─── 路径常量 ───
ROOT = Path(__file__).resolve().parents[2]
COMPARE_DIR = ROOT / "docs" / "h5_ui" / "compare"
H5_PAGES_DIR = ROOT / "docs" / "h5_ui" / "pages"

# ─── 截图参数 ───
VIEWPORT_W = 430
VIEWPORT_H = 752
DPR = 1.5
TARGET_W = 645   # 430 × 1.5
TARGET_H = 1128  # 752 × 1.5
STEP_PX = 600    # 固定步长（逻辑像素）
SINGLE_SCREEN_THRESHOLD = 10  # maxScroll ≤ 此值视为单屏

H5_BASE_URL = "http://127.0.0.1:5500/docs/h5_ui/pages"


# ═══════════════════════════════════════════════════════════
# 页面清单（来自 design.md §5，2026-03-10 Playwright 实测）
# ═══════════════════════════════════════════════════════════

PAGE_DATA: dict[str, dict] = {
    "board-finance":              {"scrollHeight": 5600, "maxScroll": 4848, "steps": 10, "dims": 1},
    "board-coach":                {"scrollHeight": 754,  "maxScroll": 2,    "steps": 1,  "dims": 4},
    "board-customer":             {"scrollHeight": 752,  "maxScroll": 0,    "steps": 1,  "dims": 8},
    "task-detail":                {"scrollHeight": 2995, "maxScroll": 2243, "steps": 5,  "dims": 1},
    "task-detail-callback":       {"scrollHeight": 2397, "maxScroll": 1645, "steps": 4,  "dims": 1},
    "task-detail-priority":       {"scrollHeight": 2389, "maxScroll": 1637, "steps": 4,  "dims": 1},
    "task-detail-relationship":   {"scrollHeight": 2275, 
"maxScroll": 1523, "steps": 4,  "dims": 1},
    "coach-detail":               {"scrollHeight": 2918, "maxScroll": 2166, "steps": 5,  "dims": 1},
    "customer-detail":            {"scrollHeight": 3070, "maxScroll": 2318, "steps": 5,  "dims": 1},
    "performance":                {"scrollHeight": 7705, "maxScroll": 6953, "steps": 13, "dims": 1},
    "task-list":                  {"scrollHeight": 1428, "maxScroll": 676,  "steps": 3,  "dims": 1},
    "my-profile":                 {"scrollHeight": 752,  "maxScroll": 0,    "steps": 1,  "dims": 1},
    "customer-service-records":   {"scrollHeight": 961,  "maxScroll": 209,  "steps": 2,  "dims": 1},
    "performance-records":        {"scrollHeight": 2677, "maxScroll": 1925, "steps": 5,  "dims": 1},
    "chat":                       {"scrollHeight": 1061, "maxScroll": 309,  "steps": 2,  "dims": 1},
    "chat-history":               {"scrollHeight": 752,  "maxScroll": 0,    "steps": 1,  "dims": 1},
    "notes":                      {"scrollHeight": 1709, "maxScroll": 957,  "steps": 3,  "dims": 1},
}

# board-coach 排序维度
BOARD_COACH_DIMS = ["perf", "salary", "sv", "task"]
# board-customer 客户维度
BOARD_CUSTOMER_DIMS = ["recall", "potential", "balance", "recharge",
                       "recent", "spend60", "freq60", "loyal"]


# ═══════════════════════════════════════════════════════════
# 核心计算
# ═══════════════════════════════════════════════════════════

def compute_scroll_sequence(scroll_height: int, viewport_height: int = VIEWPORT_H) -> list[int]:
    """根据 scrollHeight 和 viewportHeight 计算固定步长的 scrollTop 序列。

    规则（design.md §2.2）：
      maxScroll = scrollHeight - viewportHeight
      maxScroll ≤ 10 → 单屏 [0]
      N = floor(maxScroll / 600) + 1
      序列：0, 600, 1200, ... 最后一步 clamp 到 maxScroll
    """
    max_scroll = scroll_height - viewport_height
    if max_scroll <= SINGLE_SCREEN_THRESHOLD:
        return [0]

    sequence = []
    for i in range(math.floor(max_scroll / STEP_PX) + 1):
        target = i * STEP_PX
        if target >= max_scroll:
            target = max_scroll
        sequence.append(target)

    if sequence[-1] != max_scroll:
        sequence.append(max_scroll)

    return sequence


def page_output_dir(page_name: str, dimension: str | None = None) -> Path:
    """返回页面的截图输出目录。多维度页面按维度分子目录。"""
    base = COMPARE_DIR / page_name
    if dimension:
        return base / dimension
    return base


def h5_url(page_name: str) -> str:
    """返回 H5 页面的 Live Server URL。"""
    return f"{H5_BASE_URL}/{page_name}.html"


# ═══════════════════════════════════════════════════════════
# CLI 命令
# ═══════════════════════════════════════════════════════════

def cmd_calc(scroll_height: int):
    """计算 scrollTop 序列"""
    seq = compute_scroll_sequence(scroll_height)
    max_scroll = scroll_height - VIEWPORT_H
    print(f"scrollHeight: {scroll_height}px")
    print(f"viewportHeight: {VIEWPORT_H}px")
    print(f"maxScroll: {max_scroll}px")
    print(f"步数: {len(seq)}")
    print(f"序列: {seq}")


def cmd_status(page_name: str | None = None):
    """查看截图状态"""
    pages = [page_name] if page_name else list(PAGE_DATA.keys())

    print(f"\n{'页面':<30} {'步数':>4} {'维度':>4} {'H5':>4} {'MP':>4} {'diff':>4}")
    print("-" * 60)

    for name in pages:
        data = PAGE_DATA.get(name)
        if not data:
            print(f"  未知页面: {name}")
            continue

        dims = data["dims"]
        steps = data["steps"]

        if dims > 1:
            # 多维度页面：检查每个维度子目录
            dim_list = BOARD_COACH_DIMS if name == "board-coach" else BOARD_CUSTOMER_DIMS
            for dim in dim_list:
                out_dir = page_output_dir(name, dim)
                h5_count = len(list(out_dir.glob("h5--step-*.png"))) if out_dir.exists() else 0
                mp_count = len(list(out_dir.glob("mp--step-*.png"))) if out_dir.exists() else 0
                diff_count = len(list(out_dir.glob("diff--step-*.png"))) if out_dir.exists() else 0
                print(f"  {name}/{dim:<22} {steps:>4} {1:>4} {h5_count:>4} {mp_count:>4} {diff_count:>4}")
        else:
            out_dir = page_output_dir(name)
            h5_count = len(list(out_dir.glob("h5--step-*.png"))) if out_dir.exists() else 0
            mp_count = len(list(out_dir.glob("mp--step-*.png"))) if out_dir.exists() else 0
            diff_count = len(list(out_dir.glob("diff--step-*.png"))) if out_dir.exists() else 0
            print(f"  {name:<30} {steps:>4} {dims:>4} {h5_count:>4} {mp_count:>4} {diff_count:>4}")


def cmd_list():
    """列出所有页面及参数"""
    total_units = 0
    print(f"\n{'#':>2} {'页面':<30} {'scrollH':>7} {'maxScr':>7} {'步数':>4} {'维度':>4} {'单元':>4}")
    print("-" * 70)
    for i, (name, data) in enumerate(PAGE_DATA.items(), 1):
        units = data["steps"] * data["dims"]
        total_units += units
        seq = compute_scroll_sequence(data["scrollHeight"])
        print(f"{i:>2} {name:<30} {data['scrollHeight']:>7} {data['maxScroll']:>7} "
              f"{data['steps']:>4} {data['dims']:>4} {units:>4}")
    print("-" * 70)
    print(f"   {'合计':<30} {'':>7} {'':>7} {'':>4} {'':>4} {total_units:>4}")


def cmd_report(page_name: str):
    """读取已有 diff 图的差异率数据，生成/更新 report.md"""
    out_dir = page_output_dir(page_name)
    report_path = out_dir / "report.md"

    if not out_dir.exists():
        print(f"目录不存在: {out_dir.relative_to(ROOT)}")
        return

    # 查找 diff 图
    diff_files = sorted(out_dir.glob("diff--step-*.png"))
    if not diff_files:
        print(f"未找到 diff 图: {out_dir.relative_to(ROOT)}/diff--step-*.png")
        return

    print(f"\n差异率报告: {page_name}")
    print(f"diff 图数量: {len(diff_files)}")
    print(f"报告路径: {report_path.relative_to(ROOT)}")
    print(f"\n注意：差异率数据需要从 image_compare MCP 的输出中手动填入")


def print_usage():
    print("""
用法:
  python scripts/ops/anchor_compare.py <command> [args]

命令:
  calc    <scrollHeight>   计算 scrollTop 序列
  status  [<page>]         查看截图状态（不指定页面则显示全部）
  report  <page>           生成差异率报告框架
  list                     列出所有页面及参数

截图和对比通过 MCP 工具在对话中执行：
  H5 截图 → Playwright MCP
  MP 截图 → 微信开发者工具 MCP
  像素对比 → image_compare MCP

示例:
  python scripts/ops/anchor_compare.py calc 5600
  python scripts/ops/anchor_compare.py status board-finance
  python scripts/ops/anchor_compare.py list
""")


def main():
    _ensure_utf8_stdio()

    if len(sys.argv) < 2:
        print_usage()
        sys.exit(1)

    command = sys.argv[1]

    if command in ("--help", "-h"):
        print_usage()
        return

    if command == "list":
        cmd_list()
    elif command == "calc":
        if len(sys.argv) < 3:
            print("缺少 scrollHeight 参数")
            sys.exit(1)
        cmd_calc(int(sys.argv[2]))
    elif command == "status":
        page = sys.argv[2] if len(sys.argv) >= 3 else None
        cmd_status(page)
    elif command == "report":
        if len(sys.argv) < 3:
            print("缺少 page 参数")
            sys.exit(1)
        cmd_report(sys.argv[2])
    else:
        print(f"未知命令: {command}")
        print_usage()
        sys.exit(1)


if __name__ == "__main__":
    main()
