#!/usr/bin/env python3
"""E2E smoke for insurance-schedule-renewal on shared insurance DB."""
from __future__ import annotations

import json
import os
import sqlite3
import subprocess
import sys
import tempfile
from datetime import datetime, timedelta
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}")


SCHEDULE_CLI = _resolve_cli("insurance-schedule-renewal")
CUSTOMER_CLI = _resolve_cli("insurance-customer-policy")


def _run_json(cmd: list[str], env: dict[str, str], label: str, timeout: int = 120) -> dict:
    r = subprocess.run(cmd, env=env, capture_output=True, text=True, encoding="utf-8", timeout=timeout)
    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_schedule(*args: str) -> dict:
    cmd = [sys.executable, str(SCHEDULE_CLI), *args]
    env = {**os.environ, "PYTHONIOENCODING": "utf-8"}
    return _run_json(cmd, env, "schedule", timeout=120)


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", timeout=60)


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 main() -> int:
    tmp = tempfile.mkdtemp(prefix="ins_sched_smoke_")
    shared = str(Path(tmp) / "insurance.sqlite3")
    os.environ["INSURANCE_DB_PATH"] = shared
    os.environ["INSURANCE_SCHEDULE_DB_PATH"] = shared
    os.environ["INSURANCE_CUSTOMER_DB_PATH"] = shared

    today = datetime.now()
    in_15 = (today + timedelta(days=15)).strftime("%Y-%m-%d")
    in_45 = (today + timedelta(days=45)).strftime("%Y-%m-%d")
    long_ago = (today - timedelta(days=400)).strftime("%Y-%m-%d")

    print("[setup] customers")
    assert_ok(run_customer("customer-add", "--name", "张先生", "--phone", "13800138000",
                           "--age", "35", "--income", "300000",
                           "--household", '{"spouse":true,"children":2}',
                           "--birthday", f"1989-{today.month:02d}-09"))
    assert_ok(run_customer("customer-add", "--name", "李女士", "--phone", "13900139000",
                           "--age", "40", "--birthday",
                           f"1985-{(today.month % 12) + 1:02d}-15"))
    assert_ok(run_customer("customer-add", "--name", "王先生", "--phone", "13700137000", "--age", "50"))

    print("[setup] policies")
    p1 = assert_ok(run_customer("policy-add", "--customer-id", "C001",
                                "--company", "A保险", "--product", "重疾险XX",
                                "--type", "重疾险", "--coverage", "500000", "--premium", "8000",
                                "--effective-date", long_ago,
                                "--expire-date", in_15,
                                "--next-pay-date", in_15))
    assert p1["id"] == "P001"
    eff_recent = (today - timedelta(days=20)).strftime("%Y-%m-%d")  # 周年月份
    eff_recent = f"{today.year - 2}-{today.month:02d}-15"
    assert_ok(run_customer("policy-add", "--customer-id", "C002",
                           "--company", "B保险", "--product", "百万医疗",
                           "--type", "医疗险", "--coverage", "1000000", "--premium", "500",
                           "--effective-date", eff_recent,
                           "--expire-date", in_45))
    assert_ok(run_customer("policy-add", "--customer-id", "C003",
                           "--company", "C保险", "--product", "意外险",
                           "--type", "意外险", "--coverage", "500000", "--premium", "300",
                           "--effective-date", "2020-01-01"))

    print("[setup] followups (C001 has recent, C002/C003 backdated to >30d/>60d)")
    assert_ok(run_customer("followup-add", "--customer-id", "C001", "--content", "刚刚跟进过"))
    # Backdate customer created_at so 'lapsed' logic kicks in.
    conn = sqlite3.connect(os.environ["INSURANCE_DB_PATH"])
    backdated_30 = (today - timedelta(days=45)).strftime("%Y-%m-%d %H:%M:%S")
    backdated_60 = (today - timedelta(days=80)).strftime("%Y-%m-%d %H:%M:%S")
    conn.execute("UPDATE customers SET created_at=? WHERE id='C002'", (backdated_30,))
    conn.execute("UPDATE customers SET created_at=? WHERE id='C003'", (backdated_60,))
    conn.commit()
    conn.close()

    print("[1] renewal-query days=30 (P001 expire in 15d)")
    d = assert_ok(run_schedule("renewal-query", "--days", "30"))
    assert any(it["policy_id"] == "P001" for it in d["items"]), d
    assert d["items"][0]["customer_name"] == "张先生", d
    assert d["count"] >= 1

    print("[2] renewal-query days=60 (catches P002 too)")
    d = assert_ok(run_schedule("renewal-query", "--days", "60"))
    assert any(it["policy_id"] == "P002" for it in d["items"]), d

    print("[3] renewal-remind --mark-sent (first run -> new)")
    d = assert_ok(run_schedule("renewal-remind", "--days", "30", "--mark-sent"))
    assert d["new_count"] >= 1
    assert d["skipped_count"] == 0

    print("[4] renewal-remind same bucket (second run -> already_sent)")
    d = assert_ok(run_schedule("renewal-remind", "--days", "30", "--mark-sent"))
    assert d["new_count"] == 0
    assert d["skipped_count"] >= 1

    print("[5] followup-check days=30 (C002, C003 lapsed; C001 recent)")
    d = assert_ok(run_schedule("followup-check", "--days", "30"))
    cids = [c["customer_id"] for c in d["items"]]
    assert "C001" not in cids
    assert "C002" in cids and "C003" in cids

    print("[6] followup-remind dedup")
    a = assert_ok(run_schedule("followup-remind", "--days", "30", "--mark-sent"))
    assert a["new_count"] >= 2 and a["skipped_count"] == 0
    b = assert_ok(run_schedule("followup-remind", "--days", "30", "--mark-sent"))
    assert b["new_count"] == 0 and b["skipped_count"] >= 2

    print("[7] dormant-query days=60 (only C003 lapsed >60d)")
    d = assert_ok(run_schedule("dormant-query", "--days", "60"))
    cids = [c["customer_id"] for c in d["items"]]
    assert "C003" in cids and "C001" not in cids, d

    print("[8] dormant-wake (script generated)")
    d = assert_ok(run_schedule("dormant-wake", "--days", "60"))
    angles = {it["angle"] for it in d["items"]}
    assert angles, d
    assert all(it["script"] for it in d["items"]), d

    print("[9] special-date-query birthday (current month)")
    d = assert_ok(run_schedule("special-date-query", "--type", "birthday",
                               "--month", str(today.month)))
    assert any(it["customer_id"] == "C001" for it in d["items"]), d

    print("[10] special-date-query anniversary (current month)")
    d = assert_ok(run_schedule("special-date-query", "--type", "anniversary",
                               "--month", str(today.month)))
    assert any(it["policy_id"] == "P002" for it in d["items"]), d

    print("[11] daily-summary")
    d = assert_ok(run_schedule("daily-summary"))
    assert d["summary"]["renewal_30d"] >= 1
    assert "续保提醒" in d["markdown"]

    print("[12] dashboard")
    d = assert_ok(run_schedule("dashboard", "--json"))
    assert d["skill"] == "insurance-schedule-renewal"

    print("ALL OK")
    return 0


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