"""司机端小程序 fixture — 通过 subprocess 驱动 miniprogram-automator (Node.js)。

原理:
    Python pytest → subprocess → node runner.js → miniprogram-automator
                                           → 微信开发者工具 → 小程序
    返回 JSON: {"ok": true/false, "message": "...", "screenshot": "path"}

前置条件:
    1. 微信开发者工具已安装 + 开启服务端口
    2. npm install（在 tests/web/mini_program/automator/ 下）
    3. uni-app 已编译为微信小程序
"""

import json
import subprocess
from datetime import datetime
from pathlib import Path

import pytest

PROJECT_ROOT = Path(__file__).parent.parent.parent.parent
RUNNER = Path(__file__).parent / "automator" / "runner.js"
SCREENSHOTS_DIR = Path("output/screenshots")


def _run_runner(project_path: str, action: str, **kwargs) -> dict:
    """调用 node runner.js，返回解析后的 JSON。"""
    cmd = [
        "node", str(RUNNER),
        "--action", action,
        "--project-path", project_path,
        "--timeout", str(kwargs.get("timeout", 30000)),
    ]
    for key, value in kwargs.items():
        if value is not None and key not in ("timeout",):
            cmd.extend([f"--{key.replace('_', '-')}", str(value)])

    result = subprocess.run(cmd, capture_output=True, text=True, timeout=120, cwd=str(PROJECT_ROOT))

    try:
        data = json.loads(result.stdout.strip())
    except json.JSONDecodeError:
        data = {"ok": False, "message": result.stderr or result.stdout, "screenshot": None}

    data["_raw_stdout"] = result.stdout
    data["_raw_stderr"] = result.stderr
    return data


@pytest.fixture
def mini_program_config(config):
    """小程序配置。"""
    return config["mini_program"]


@pytest.fixture
def run_mini_action(mini_program_config):
    """调用 miniprogram-automator 执行一个操作并返回结果。

    Usage:
        result = run_mini_action("smoke")
        assert result["ok"], result["message"]
        # result["screenshot"] 是截图路径
    """

    def _run(action: str, **kwargs) -> dict:
        project_path = mini_program_config.get("project_path", ".")
        dev_tool = mini_program_config.get("dev_tool_path", "")
        timeout = mini_program_config.get("timeout_seconds", 120) * 1000

        return _run_runner(
            project_path,
            action,
            dev_tool_path=dev_tool,
            timeout=timeout,
            **kwargs,
        )

    return _run


def save_failure_screenshot(name: str) -> str:
    """保存 Python 端的失败截图（如 runner 调用超时）。"""
    scenario_dir = SCREENSHOTS_DIR / "mini_program"
    scenario_dir.mkdir(parents=True, exist_ok=True)
    ts = datetime.now().strftime("%Y%m%d_%H%M%S")
    path = str(scenario_dir / f"FAIL_{name}_{ts}.png")
    # 此层无法截图小程序，创建空标记文件用于日志追溯
    Path(path).touch()
    return path
