#!/usr/bin/env python3
"""E2E smoke for insurance-product-analysis over shared insurance DB."""
from __future__ import annotations

import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path

HERE = Path(__file__).resolve().parent


def _discover_skills_root() -> Path:
    env = os.environ.get("INSURANCE_SKILLS_ROOT") or os.environ.get("SKILLS_ROOT")
    if env:
        p = Path(env).expanduser().resolve()
        if p.is_dir():
            return p
    candidates = [HERE.parents[2], HERE.parents[1], Path("/app/skills"), Path.cwd() / "skills"]
    for c in candidates:
        try:
            if (c / "insurance-customer-policy").is_dir():
                return c.resolve()
        except OSError:
            continue
    raise SystemExit("[FAIL] cannot discover skills root for smoke test")


def _resolve_customer_pkg(skills_root: Path) -> Path:
    candidates = [
        skills_root / "insurance-customer-policy" / "scripts",
        skills_root / "insurance-customer-policy" / "src" / "scripts",
        skills_root / "insurance-customer-policy" / "src" / "src",
    ]
    for p in candidates:
        try:
            if (p / "insurance_customer_cli" / "__init__.py").is_file():
                return p
        except OSError:
            continue
    raise SystemExit("[FAIL] cannot locate insurance_customer_cli package for smoke test")


SKILLS_ROOT = _discover_skills_root()
CUSTOMER_PKG = _resolve_customer_pkg(SKILLS_ROOT)


def _resolve_cli(skill_folder: str) -> Path:
    candidates = [
        SKILLS_ROOT / skill_folder / "scripts" / "cli.py",
        SKILLS_ROOT / skill_folder / "src" / "scripts" / "cli.py",
    ]
    for p in candidates:
        if p.is_file():
            return p
    raise SystemExit(f"[FAIL] cannot locate cli.py for {skill_folder}")


PRODUCT_CLI = _resolve_cli("insurance-product-analysis")
CUSTOMER_CLI = _resolve_cli("insurance-customer-policy")


def _run_json(cmd: list[str], env: dict[str, str], label: str) -> dict:
    r = subprocess.run(cmd, env=env, capture_output=True, text=True, encoding="utf-8", timeout=120)
    if r.returncode not in (0, 1):
        raise SystemExit(f"{label} rc={r.returncode}\nCMD: {' '.join(cmd)}\nSTDOUT:\n{r.stdout}\nSTDERR:\n{r.stderr}")
    out = (r.stdout or "").strip()
    if not out:
        raise SystemExit(f"{label} empty stdout\nCMD: {' '.join(cmd)}\nrc={r.returncode}\nSTDERR:\n{r.stderr}")
    try:
        return json.loads(out)
    except json.JSONDecodeError as e:
        raise SystemExit(f"{label} bad json: {e}\nCMD: {' '.join(cmd)}\nSTDOUT:\n{out}\nSTDERR:\n{r.stderr}")


def run_product(*args: str) -> dict:
    cmd = [sys.executable, str(PRODUCT_CLI), *args]
    env = {**os.environ, "PYTHONIOENCODING": "utf-8"}
    return _run_json(cmd, env, "product")


def run_customer(*args: str) -> dict:
    cmd = [sys.executable, str(CUSTOMER_CLI), *args]
    env = {**os.environ, "PYTHONIOENCODING": "utf-8"}
    return _run_json(cmd, env, "customer")


def assert_ok(d: dict, *args: str) -> dict:
    if not d.get("ok"):
        raise SystemExit(f"expected ok=True got {d} args={args}")
    return d


def assert_err(d: dict, code: str, *args: str) -> None:
    if d.get("ok") or d.get("error") != code:
        raise SystemExit(f"expected error={code} got {d} args={args}")


def main() -> int:
    tmp = tempfile.mkdtemp(prefix="ins_prod_smoke_")
    shared = str(Path(tmp) / "insurance.sqlite3")
    os.environ["INSURANCE_DB_PATH"] = shared
    os.environ["INSURANCE_PRODUCT_DB_PATH"] = shared
    os.environ["INSURANCE_CUSTOMER_DB_PATH"] = shared

    print("[setup] seed customer-policy data")
    assert_ok(run_customer("customer-add", "--name", "张先生", "--phone", "13800138000",
                           "--age", "35", "--income", "300000",
                           "--household", '{"spouse":true,"children":2}'))
    assert_ok(run_customer("customer-add", "--name", "李女士", "--phone", "13900139000",
                           "--age", "28", "--income", "150000"))
    assert_ok(run_customer("policy-add", "--customer-id", "C001",
                           "--company", "A保险", "--product", "百万医疗",
                           "--type", "医疗险", "--coverage", "1000000", "--premium", "500",
                           "--effective-date", "2024-01-01", "--pay-period", "1年"))
    assert_ok(run_customer("followup-add", "--customer-id", "C001", "--content", "刚刚跟进"))

    print("[1] product-add")
    p1 = assert_ok(run_product("product-add", "--name", "XX重疾险2024",
                               "--company", "A保险公司", "--type", "重疾险",
                               "--coverage-range", "10万-100万",
                               "--premium-range", "3000-15000",
                               "--age-range", "0-55岁",
                               "--highlights", "覆盖120种重疾|轻症豁免|保额递增",
                               "--raw-text", "保120种重疾，等待期90天..."))
    assert p1["id"]
    assert_ok(run_product("product-add", "--name", "YY重疾险2024",
                          "--company", "B保险公司", "--type", "重疾险",
                          "--coverage-range", "30万-200万",
                          "--premium-range", "5000-20000",
                          "--age-range", "0-55岁",
                          "--highlights", "保额翻倍|覆盖180种重疾"))

    print("[2] product-add: duplicate")
    assert_err(run_product("product-add", "--name", "XX重疾险2024",
                           "--company", "A", "--type", "重疾险"), "duplicate_product")

    print("[3] product-query")
    d = assert_ok(run_product("product-query", "--type", "重疾险"))
    assert d["count"] == 2

    print("[4] product-update + cache invalidation")
    assert_ok(run_product("product-update", "--name", "XX重疾险2024",
                          "--set", '{"highlights":["新亮点A","新亮点B"]}'))
    d = assert_ok(run_product("product-query", "--name", "XX重疾险2024"))
    assert "新亮点A" in d["products"][0]["highlights"]

    print("[5] product-analyze (no cache → needs_llm)")
    d = run_product("product-analyze", "--product", "XX重疾险2024")
    assert d.get("error") == "needs_llm", d
    assert "prompt_template" in d

    print("[6] analysis-write + product-analyze (cache hit)")
    assert_ok(run_product("analysis-write", "--product", "XX重疾险2024",
                          "--result", json.dumps({
                              "key_terms": ["保120种重疾", "等待期90天"],
                              "selling_points": ["保额递增", "轻症豁免", "费率低"],
                              "fit_audience": ["25-45岁", "年收入20w+"],
                              "pitch_script": "您已有医疗险..."
                          }, ensure_ascii=False)))
    d = assert_ok(run_product("product-analyze", "--product", "XX重疾险2024"))
    assert d["result"]["from_cache"] is True
    assert "保额递增" in d["result"]["selling_points"]

    print("[7] gap-analysis (forwarded)")
    d = assert_ok(run_product("gap-analysis", "--customer-id", "C001"))
    assert "重疾险" in d["result"]["gaps"]
    d = assert_ok(run_product("gap-analysis", "--all", "--gap-type", "重疾险"))
    assert d["count"] >= 1

    print("[8] customer-match (product → customers)")
    d = assert_ok(run_product("customer-match", "--product", "XX重疾险2024"))
    assert any(m["matches_gap"] for m in d["matches"])
    top = d["matches"][0]
    assert top["score"] >= 100, top

    print("[9] customer-match (customer → products)")
    d = assert_ok(run_product("customer-match", "--customer-id", "C001"))
    assert d["matches"], d
    assert d["matches"][0]["matches_gap"] is True

    print("[10] product-compare")
    d = assert_ok(run_product("product-compare", "--product-a", "XX重疾险2024",
                              "--product-b", "YY重疾险2024"))
    assert any(r["field"] == "公司" for r in d["compare"])

    print("[11] dashboard")
    d = assert_ok(run_product("dashboard", "--json"))
    assert d["products_total"] == 2

    print("[12] product-delete")
    assert_err(run_product("product-delete", "--name", "YY重疾险2024"), "need_confirm")
    assert_ok(run_product("product-delete", "--name", "YY重疾险2024", "--yes"))

    print("ALL OK")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
