"""Comprehensive System & Website Diagnostic & Audit Script for DSCons (Async httpx).

Scans:
1. System Services (PostgreSQL, Cloudflare Tunnel, Uvicorn auto-reload, LM Studio, Tailscale/SSH).
2. Public Website (https://dinhsonconstruction.com) vs Local (http://127.0.0.1:8000).
3. Cache-Control headers (anti-caching verification for live reload UI).
4. Major UI Pages & API Endpoints (both public & authenticated).
5. Database Connectivity & Ground Truth records.
6. Generates audit JSON and Markdown reports.
"""

from __future__ import annotations

import asyncio
import json
import socket
import ssl
import sys
import time
from datetime import datetime, timezone
from pathlib import Path

import httpx

# Ensure project root is on sys.path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

LOGS_DIR = PROJECT_ROOT / "logs"
LOGS_DIR.mkdir(exist_ok=True)

REPORT_JSON = LOGS_DIR / "system_diagnostic_latest.json"
REPORT_MD = LOGS_DIR / "system_diagnostic_report.md"

BASE_URL_PUBLIC = "https://dinhsonconstruction.com"
BASE_URL_LOCAL = "http://127.0.0.1:8000"
DEV_AUTH_TOKEN = "dev-test-token"


def check_port(host: str, port: int, timeout: float = 0.5) -> bool:
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except (TimeoutError, ConnectionRefusedError, OSError):
        return False


async def test_endpoint_async(
    client: httpx.AsyncClient, base_url: str, path: str, auth_token: str | None = None
) -> dict:
    url = f"{base_url}{path}"
    headers = {"User-Agent": "DSCons-HealthChecker/1.0"}
    if auth_token:
        headers["Authorization"] = f"Bearer {auth_token}"

    start_t = time.perf_counter()
    result = {
        "path": path,
        "url": url,
        "authenticated": bool(auth_token),
        "status_code": None,
        "latency_ms": None,
        "cache_control": None,
        "content_type": None,
        "success": False,
        "error": None,
    }

    try:
        resp = await client.get(
            url, headers=headers, follow_redirects=True, timeout=5.0
        )
        latency = (time.perf_counter() - start_t) * 1000.0
        result["status_code"] = resp.status_code
        result["latency_ms"] = round(latency, 2)
        result["cache_control"] = resp.headers.get("cache-control")
        result["content_type"] = resp.headers.get("content-type")
        result["server"] = resp.headers.get("server")
        result["cf_ray"] = resp.headers.get("cf-ray")
        result["success"] = 200 <= resp.status_code < 400
    except httpx.HTTPStatusError as e:
        latency = (time.perf_counter() - start_t) * 1000.0
        result["status_code"] = e.response.status_code
        result["latency_ms"] = round(latency, 2)
        result["cache_control"] = e.response.headers.get("cache-control")
        result["content_type"] = e.response.headers.get("content-type")
        result["error"] = f"HTTP {e.response.status_code}"
        result["success"] = 200 <= e.response.status_code < 400
    except Exception as e:
        result["error"] = str(e)
        result["success"] = False

    return result


def check_ssl_cert(hostname: str = "dinhsonconstruction.com", port: int = 443) -> dict:
    try:
        ctx = ssl.create_default_context()
        with ctx.wrap_socket(socket.socket(), server_hostname=hostname) as s:
            s.settimeout(2.0)
            s.connect((hostname, port))
            cert = s.getpeercert()
            issuer = dict(x[0] for x in cert.get("issuer", []))
            subject = dict(x[0] for x in cert.get("subject", []))
            return {
                "valid": True,
                "issuer_org": issuer.get("organizationName", "Unknown"),
                "issuer_cn": issuer.get("commonName", "Unknown"),
                "not_after": cert.get("notAfter"),
                "not_before": cert.get("notBefore"),
                "subject_cn": subject.get("commonName", "Unknown"),
            }
    except Exception as e:
        return {"valid": False, "error": str(e)}


def check_db_integrity() -> dict:
    try:
        from app.core.postgres import PostgresClient

        client = PostgresClient()
        conn = client.get_connection()
        cur = conn.cursor()
        counts = {}
        for tbl in [
            "projects",
            "erp_partners",
            "erp_invoices",
            "erp_equipment",
            "employees",
            "erp_documents",
        ]:
            cur.execute(f"SELECT count(*) as c FROM {tbl}")
            counts[tbl] = cur.fetchone()["c"]
        conn.close()
        return {
            "status": "connected",
            "postgres_available": True,
            "counts": counts,
        }
    except Exception as e:
        return {"status": "error", "postgres_available": False, "error": str(e)}


async def run_full_diagnostic_async():
    now_utc = datetime.now(timezone.utc).isoformat()
    now_local = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    print(f"[{now_local}] Starting comprehensive DSCons health audit (async)...")

    # 1. System Services Check
    services = {
        "fastapi_uvicorn_8000": {
            "name": "FastAPI / Uvicorn Server",
            "port": 8000,
            "running": check_port("127.0.0.1", 8000),
            "expected_flag": "--reload",
        },
        "postgresql_5432": {
            "name": "PostgreSQL Database",
            "port": 5432,
            "running": check_port("127.0.0.1", 5432),
        },
        "lm_studio_1234": {
            "name": "LM Studio Local LLM Engine",
            "port": 1234,
            "running": check_port("127.0.0.1", 1234),
        },
        "ssh_server_22": {
            "name": "OpenSSH Windows Server",
            "port": 22,
            "running": check_port("127.0.0.1", 22),
        },
    }

    # 2. SSL & Domain Edge
    ssl_info = check_ssl_cert("dinhsonconstruction.com")

    # 3. Database Check
    db_info = check_db_integrity()

    # 4. Target Endpoints to Test
    ui_pages = [
        "/",
        "/landing",
        "/dashboard",
        "/login",
        "/projects",
        "/wbs",
        "/war-room",
        "/finance",
        "/invoices",
        "/partners",
        "/vendors",
        "/customers",
        "/employees",
        "/equipment",
        "/documents",
        "/takeoff",
        "/drawing-takeoff",
        "/site-diary",
        "/site-pwa",
        "/readiness",
        "/material-prices",
        "/material-price-comparison",
    ]

    public_api_endpoints = [
        "/health",
        "/health/readiness",
        "/docs",
        "/v1/war-room/summary",
        "/v1/desktop/health",
    ]

    authenticated_api_endpoints = [
        "/v1/company/operational-state",
        "/v1/erp/projects",
        "/v1/erp/invoices",
        "/v1/erp/equipment",
        "/v1/erp/employees",
        "/v1/erp/documents",
        "/v1/autonomous/status",
    ]

    static_assets = [
        "/static/css/erp_enterprise.css",
        "/static/js/erp_mobile_dock.js",
    ]

    # Concurrent HTTP testing using httpx
    async with httpx.AsyncClient(verify=False, timeout=5.0) as client:
        pub_tasks = []
        for path in ui_pages + public_api_endpoints + static_assets:
            pub_tasks.append(test_endpoint_async(client, BASE_URL_PUBLIC, path, None))
        for path in authenticated_api_endpoints:
            pub_tasks.append(
                test_endpoint_async(client, BASE_URL_PUBLIC, path, DEV_AUTH_TOKEN)
            )

        loc_tasks = []
        for path in ui_pages + public_api_endpoints + static_assets:
            loc_tasks.append(test_endpoint_async(client, BASE_URL_LOCAL, path, None))
        for path in authenticated_api_endpoints:
            loc_tasks.append(
                test_endpoint_async(client, BASE_URL_LOCAL, path, DEV_AUTH_TOKEN)
            )

        public_results = await asyncio.gather(*pub_tasks)
        local_results = await asyncio.gather(*loc_tasks)

    # Summarize Results
    public_passed = sum(1 for r in public_results if r["success"])
    public_failed = sum(1 for r in public_results if not r["success"])
    local_passed = sum(1 for r in local_results if r["success"])
    local_failed = sum(1 for r in local_results if not r["success"])

    # Anti-cache Verification
    cache_check = []
    for r in public_results:
        if r["path"] in ["/", "/dashboard", "/login", "/static/css/erp_enterprise.css"]:
            cc = r.get("cache_control") or ""
            is_anti_cache = "no-cache" in cc and "no-store" in cc
            cache_check.append(
                {
                    "path": r["path"],
                    "cache_control": cc,
                    "anti_cache_valid": is_anti_cache,
                }
            )

    audit_data = {
        "timestamp_utc": now_utc,
        "timestamp_local": now_local,
        "domain": "dinhsonconstruction.com",
        "services": services,
        "ssl_certificate": ssl_info,
        "database": db_info,
        "summary": {
            "public_total": len(public_results),
            "public_passed": public_passed,
            "public_failed": public_failed,
            "local_total": len(local_results),
            "local_passed": local_passed,
            "local_failed": local_failed,
            "website_healthy": (
                public_failed == 0 and services["fastapi_uvicorn_8000"]["running"]
            ),
        },
        "anti_cache_verification": cache_check,
        "public_endpoints": public_results,
        "local_endpoints": local_results,
    }

    # Save JSON Log
    with open(REPORT_JSON, "w", encoding="utf-8") as f:
        json.dump(audit_data, f, indent=2, ensure_ascii=False)

    # Generate Markdown Report
    md_lines = [
        "# DSCons ERP & Website Diagnostic Audit Report",
        f"**Audit Timestamp:** `{now_local}` (UTC: `{now_utc}`)",
        f"**Target Website:** [{BASE_URL_PUBLIC}]({BASE_URL_PUBLIC})",
        "",
        "## 1. System Services Status",
        "| Service | Target Port | Status | Details |",
        "| :--- | :---: | :---: | :--- |",
    ]

    for key, svc in services.items():
        status_icon = "🟢 UP" if svc["running"] else "🔴 DOWN"
        md_lines.append(
            f"| {svc['name']} | `{svc['port']}` | {status_icon} | Local Port `{svc['port']}` |"
        )

    md_lines.extend(
        [
            "",
            "## 2. SSL / Cloudflare Edge Health",
            f"- **SSL Validity:** {'🟢 Valid' if ssl_info.get('valid') else '🔴 Invalid'}",
            f"- **Issuer:** `{ssl_info.get('issuer_org', 'N/A')}` ({ssl_info.get('issuer_cn', 'N/A')})",
            f"- **Expires After:** `{ssl_info.get('not_after', 'N/A')}`",
            f"- **Subject CN:** `{ssl_info.get('subject_cn', 'N/A')}`",
            "",
            "## 3. Database Status (PostgreSQL Ground Truth)",
            f"- **Connection:** {'🟢 Connected' if db_info.get('postgres_available') else '🔴 Error'}",
        ]
    )

    if db_info.get("counts"):
        for tbl, cnt in db_info["counts"].items():
            md_lines.append(f"- **{tbl}:** `{cnt:,}` records")

    md_lines.extend(
        [
            "",
            "## 4. Anti-Cache Header Verification (`Cache-Control: no-cache, no-store, must-revalidate`)",
            "Ensures client browsers always receive real-time code without stale browser caching:",
            "| Route | Cache-Control Header | Anti-Cache Compliant |",
            "| :--- | :--- | :---: |",
        ]
    )

    for cc in cache_check:
        icon = "✅ PASS" if cc["anti_cache_valid"] else "⚠️ WARN"
        md_lines.append(f"| `{cc['path']}` | `{cc['cache_control']}` | {icon} |")

    md_lines.extend(
        [
            "",
            "## 5. Website & API Endpoints Verification",
            f"**Public Domain:** {public_passed}/{len(public_results)} endpoints responding with HTTP 200/300.",
            "",
            "| Route | Type | Auth Required | Public Status | Public Latency | Local Status | Local Latency |",
            "| :--- | :---: | :---: | :---: | :---: | :---: | :---: |",
        ]
    )

    for pub, loc in zip(public_results, local_results):
        r_type = (
            "Page"
            if pub["path"] in ui_pages
            else ("Asset" if pub["path"] in static_assets else "API")
        )
        auth_tag = "🔒 Bearer Token" if pub["authenticated"] else "🔓 Public"
        pub_st = (
            f"🟢 {pub['status_code']}"
            if pub["success"]
            else f"🔴 {pub['status_code']} ({pub.get('error')})"
        )
        loc_st = (
            f"🟢 {loc['status_code']}"
            if loc["success"]
            else f"🔴 {loc['status_code']} ({loc.get('error')})"
        )
        pub_lat = f"{pub['latency_ms']} ms" if pub["latency_ms"] else "N/A"
        loc_lat = f"{loc['latency_ms']} ms" if loc["latency_ms"] else "N/A"
        md_lines.append(
            f"| `{pub['path']}` | {r_type} | {auth_tag} | {pub_st} | {pub_lat} | {loc_st} | {loc_lat} |"
        )

    md_lines.extend(
        [
            "",
            "---",
            f"*Report automatically generated by DSCons Health Diagnostics Suite on {now_local}*",
        ]
    )

    with open(REPORT_MD, "w", encoding="utf-8") as f:
        f.write("\n".join(md_lines))

    print(f"[{now_local}] Diagnostic complete!")
    print(f"- Public endpoints: {public_passed}/{len(public_results)} PASS")
    print(f"- Local endpoints: {local_passed}/{len(local_results)} PASS")
    print(f"- Reports saved to:\n  - {REPORT_JSON}\n  - {REPORT_MD}")

    return audit_data


def main():
    asyncio.run(run_full_diagnostic_async())


if __name__ == "__main__":
    main()
