from __future__ import annotations

import argparse
import json
import os
from pathlib import Path
import sys
import time

import httpx
from sqlalchemy import create_engine, text

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

from services.shared.security import issue_app_token


def _load_env_file(path: str) -> None:
    env_path = Path(path).expanduser().resolve()
    if not env_path.exists() or not env_path.is_file():
        return
    for line in env_path.read_text(encoding="utf-8").splitlines():
        stripped = line.strip()
        if not stripped or stripped.startswith("#") or "=" not in stripped:
            continue
        key, value = stripped.split("=", 1)
        key = key.strip()
        if key and key not in os.environ:
            os.environ[key] = value.strip()


def _bool_env(name: str, default: bool) -> bool:
    raw = os.getenv(name)
    if raw is None:
        return default
    return raw.strip().lower() in {"1", "true", "yes", "on"}


def _ops_headers() -> dict[str, str]:
    if _bool_env("ALLOW_LEGACY_HEADER_AUTH", True):
        return {"X-User": "admin", "X-Role": "admin"}
    token = issue_app_token(
        subject="ops:track9-check",
        username="track9-check",
        role="admin",
        auth_source="service",
        provider="track9-script",
        ttl_seconds=300,
    )
    return {"Authorization": f"Bearer {token}"}


def _get_json(url: str) -> dict:
    with httpx.Client(timeout=10, trust_env=False) as client:
        response = client.get(url, headers=_ops_headers())
        response.raise_for_status()
        return response.json()


def _wait_for_ami_connected(base_url: str, retries: int = 8, delay_seconds: float = 1.0) -> dict:
    last_status: dict = {}
    for _ in range(retries):
        status = _get_json(f"{base_url.rstrip('/')}/proxy/asterisk-bridge/asterisk/status")
        last_status = status
        if status.get("ami_connected"):
            return status
        time.sleep(delay_seconds)
    return last_status


def _table_exists(conn, name: str) -> bool:
    try:
        conn.execute(text(f"SELECT 1 FROM {name} LIMIT 1"))
        return True
    except Exception:  # noqa: BLE001
        return False


def _scalar(conn, sql: str) -> int:
    value = conn.execute(text(sql)).scalar()
    return int(value or 0)


def main() -> int:
    parser = argparse.ArgumentParser(description="Track 9 Asterisk integration acceptance validator")
    parser.add_argument("--base-url", default="http://127.0.0.1:8080")
    parser.add_argument("--env-file", default=".env.production")
    parser.add_argument("--database-url", required=True)
    parser.add_argument("--require-recording", action="store_true")
    args = parser.parse_args()

    _load_env_file(args.env_file)

    failures: list[str] = []

    health = _get_json(f"{args.base_url.rstrip('/')}/proxy/asterisk-bridge/health")
    status = _wait_for_ami_connected(args.base_url)
    if health.get("status") != "ok":
        failures.append("Bridge health is not ok")
    if not status.get("ami_connected"):
        failures.append("AMI is not connected")

    engine = create_engine(args.database_url, future=True)
    with engine.begin() as conn:
        for table in ("asterisk_event_log", "asterisk_call_links", "voice_events"):
            if not _table_exists(conn, table):
                failures.append(f"Missing table: {table}")

        started = _scalar(
            conn,
            "SELECT COUNT(*) FROM asterisk_event_log WHERE ami_event_name = 'MVPCCCallStarted' AND forward_status = 'forwarded'",
        )
        call_started = _scalar(
            conn,
            "SELECT COUNT(*) FROM voice_events WHERE event_type = 'call.started' AND payload_json LIKE '%\"source\": \"asterisk\"%'",
        )
        links = _scalar(conn, "SELECT COUNT(*) FROM asterisk_call_links")
        stale_failures = _scalar(
            conn,
            "SELECT COUNT(*) FROM asterisk_event_log WHERE forward_status = 'failed'",
        )
        recordings = _scalar(
            conn,
            "SELECT COUNT(*) FROM asterisk_event_log WHERE ami_event_name = 'MVPCCRecordingReady' AND recording_id IS NOT NULL",
        )

    if started < 1:
        failures.append("No forwarded MVPCCCallStarted events")
    if call_started < 1:
        failures.append("No platform call.started events from Asterisk source")
    if links < 1:
        failures.append("No linked Asterisk calls")
    if stale_failures > 0:
        failures.append(f"Failed bridge events present: {stale_failures}")
    if args.require_recording and recordings < 1:
        failures.append("No uploaded recordings linked to Asterisk events")

    if failures:
        print("[FAIL] Track 9 validation failed")
        for item in failures:
            print(f"- {item}")
        return 1

    print("[PASS] Track 9 validation checks passed")
    print(f"- started_events: {started}")
    print(f"- platform_call_started: {call_started}")
    print(f"- call_links: {links}")
    print(f"- recording_events_with_upload: {recordings}")
    return 0


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