"""保险 4-Skill 统一路径解析（对齐美容院 skill 设计思路）。

参考 ``beauty-salon-member-appointment`` 的 ``orchestrator.py`` / ``product_service_cli``：

- ``skills_root()``：默认由包内文件向上回溯；可通过 ``INSURANCE_SKILLS_ROOT`` / ``SKILLS_ROOT``
  覆盖（云端挂载目录与仓库不一致时）。
- 兄弟 skill：``<skills_root>/<skill>/src/src/<pkg>`` 与 ``/app/skills/...`` 多候选探测。
- 显式覆盖：与各包相关的 ``INSURANCE_*_PKG``；与各 skill **入口脚本** 相关的
  ``INSURANCE_*_CLI_SCRIPT``（对齐 ``INVENTORY_SCRIPT_PATH``：直接指向 ``cli.py``）。
- 子进程：若找到 ``scripts/cli.py``，优先 ``python cli.py ...``（子进程无需 PYTHONPATH）；
  否则回退 ``PYTHONPATH`` + ``python -m <module>``。
"""
from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path
from typing import Any

# ---------------------------------------------------------------------------
# skills 根目录
# ---------------------------------------------------------------------------

ENV_SKILLS_ROOT = ("INSURANCE_SKILLS_ROOT", "SKILLS_ROOT")


def resolve_skills_root(*, anchor_file: Path, parents_up_from_file: int) -> Path:
    """由任意锚点文件回溯 ``parents_up_from_file`` 层得到 ``skills/``；支持环境变量覆盖。"""
    for key in ENV_SKILLS_ROOT:
        raw = os.environ.get(key)
        if raw:
            return Path(raw).expanduser().resolve()
    p = anchor_file.resolve()
    for _ in range(parents_up_from_file):
        p = p.parent
    return p


def skills_root_from_orchestrator(orchestrator_py: Path) -> Path:
    """``.../skills/<skill>/src/src/<pkg>/orchestrator.py`` → ``skills``（向上 5 层）。"""
    return resolve_skills_root(anchor_file=orchestrator_py, parents_up_from_file=5)


def skills_root_from_dashboard_script(dashboard_py: Path) -> Path:
    """``.../skills/<skill>/src/scripts/dashboard_all.py`` → ``skills``（向上 4 层）。"""
    return resolve_skills_root(anchor_file=dashboard_py, parents_up_from_file=4)


def skills_root_from_wrapper(wrapper_py: Path) -> Path:
    """``.../skills/<skill>/src/scripts/cli.py`` → ``skills``（向上 4 层）。"""
    return resolve_skills_root(anchor_file=wrapper_py, parents_up_from_file=4)


# ---------------------------------------------------------------------------
# 各 skill 元数据（文件夹名、python 模块名、环境变量）
# ---------------------------------------------------------------------------

SKILL_META: dict[str, dict[str, str]] = {
    "insurance-customer-policy": {
        "module": "insurance_customer_cli",
        "pkg_env": "INSURANCE_CUSTOMER_PKG",
        "cli_env": "INSURANCE_CUSTOMER_CLI_SCRIPT",
    },
    "insurance-product-analysis": {
        "module": "insurance_product_cli",
        "pkg_env": "INSURANCE_PRODUCT_PKG",
        "cli_env": "INSURANCE_PRODUCT_CLI_SCRIPT",
    },
    "insurance-schedule-renewal": {
        "module": "insurance_schedule_cli",
        "pkg_env": "INSURANCE_SCHEDULE_PKG",
        "cli_env": "INSURANCE_SCHEDULE_CLI_SCRIPT",
    },
    "insurance-sales-pipeline": {
        "module": "insurance_pipeline_cli",
        "pkg_env": "INSURANCE_PIPELINE_PKG",
        "cli_env": "INSURANCE_PIPELINE_CLI_SCRIPT",
    },
}


def resolve_pkg_parent(skills_root: Path, skill_folder: str) -> Path:
    """返回应加入 PYTHONPATH 的目录（含 ``<module>/__init__.py``）。"""
    meta = SKILL_META[skill_folder]
    pkg_name = meta["module"]
    env_pkg = meta["pkg_env"]

    if os.environ.get(env_pkg):
        return Path(os.environ[env_pkg]).expanduser().resolve()

    root = skills_root.resolve()
    candidates = [
        root / skill_folder / "src" / "src",
        Path("/app/skills") / skill_folder / "src" / "src",
        Path("/app/skills") / skill_folder / "src",
        Path("/app/skills") / skill_folder,
        root / skill_folder / "src",
        root / skill_folder,
    ]
    for c in candidates:
        try:
            if (c / pkg_name / "__init__.py").is_file():
                return c
        except OSError:
            continue
    return candidates[0]


def resolve_cli_wrapper(skills_root: Path, skill_folder: str) -> Path | None:
    """解析 ``scripts/cli.py``；支持 ``INSURANCE_*_CLI_SCRIPT`` 显式路径。"""
    meta = SKILL_META[skill_folder]
    env_cli = meta["cli_env"]
    if os.environ.get(env_cli):
        p = Path(os.environ[env_cli]).expanduser().resolve()
        return p if p.is_file() else None

    root = skills_root.resolve()
    candidates = [
        root / skill_folder / "src" / "scripts" / "cli.py",
        root / skill_folder / "scripts" / "cli.py",
        Path("/app/skills") / skill_folder / "src" / "scripts" / "cli.py",
        Path("/app/skills") / skill_folder / "scripts" / "cli.py",
    ]
    for c in candidates:
        try:
            if c.is_file():
                return c
        except OSError:
            continue
    return None


def run_skill_argv_env(
    skills_root: Path,
    skill_folder: str,
    argv: list[str],
    *,
    timeout: int = 120,
) -> subprocess.CompletedProcess[str]:
    """运行某一 insurance skill 子命令；优先 wrapper，其次 ``python -m``。"""
    meta = SKILL_META[skill_folder]
    module = meta["module"]
    cli = resolve_cli_wrapper(skills_root, skill_folder)
    env = os.environ.copy()
    env["PYTHONIOENCODING"] = "utf-8"

    if cli is not None:
        return subprocess.run(
            [sys.executable, str(cli), *argv],
            env=env,
            capture_output=True,
            text=True,
            encoding="utf-8",
            timeout=timeout,
        )

    pkg = resolve_pkg_parent(skills_root, skill_folder)
    if not (pkg / module / "__init__.py").is_file():
        return subprocess.CompletedProcess(
            args=[sys.executable, "-m", module, *argv],
            returncode=99,
            stdout="",
            stderr=f"missing package at {pkg}",
        )
    env["PYTHONPATH"] = str(pkg)
    return subprocess.run(
        [sys.executable, "-m", module, *argv],
        env=env,
        capture_output=True,
        text=True,
        encoding="utf-8",
        timeout=timeout,
    )


def bootstrap_wrapper_sys_path(wrapper_py: Path, skill_folder: str) -> Path:
    """供各 skill 的 ``scripts/cli.py`` 调用：把正确 pkg 目录插入 ``sys.path`` 首部。"""
    sr = skills_root_from_wrapper(wrapper_py)
    pkg_parent = resolve_pkg_parent(sr, skill_folder)
    ps = str(pkg_parent)
    if ps not in sys.path:
        sys.path.insert(0, ps)
    return pkg_parent
