"""
Comprehensive System & Service Diagnostic Audit for DSCons (dinhsonconstruction.com)
Checks:
1. Local FastAPI Backend & Health Endpoints
2. PostgreSQL Database Connection & Query Integrity
3. Cloudflare Tunnel status & ingress mappings
4. Tailscale Mesh Network & OpenSSH Port 22
5. Public Web Domains (dinhsonconstruction.com & erp.dinhsonconstruction.com)
6. All Key Routes HTTP Status, Content Integrity, Latency
7. Playwright Real Browser E2E Rendering & Visual Verification
8. Generates Timestamped Audit Log & Markdown Report
"""

import datetime
import os
import shutil
import socket
import ssl
import subprocess
import sys
import time
import urllib.error
import urllib.request
from pathlib import Path

# Ensure UTF-8 output on Windows console
if sys.platform == "win32":
    try:
        sys.stdout.reconfigure(encoding="utf-8")
        sys.stderr.reconfigure(encoding="utf-8")
    except Exception:
        pass


# Paths
BASE_DIR = Path("C:/Projects/DSCons")
LOGS_DIR = BASE_DIR / "logs"
REPORTS_DIR = BASE_DIR / "reports"
SNAPSHOTS_DIR = BASE_DIR / "snapshots"
ARTIFACT_DIR = Path(
    os.environ.get(
        "ANTIGRAVITY_ARTIFACT_DIR",
        r"C:\Users\Admin\.gemini\antigravity\brain\6824645b-f104-4816-a06e-09a8eecdeaec",
    )
)

LOGS_DIR.mkdir(parents=True, exist_ok=True)
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
SNAPSHOTS_DIR.mkdir(parents=True, exist_ok=True)
ARTIFACT_DIR.mkdir(parents=True, exist_ok=True)

TIMESTAMP_STR = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
LOG_FILE = LOGS_DIR / f"service_diagnostic_{TIMESTAMP_STR}.log"
REPORT_FILE = REPORTS_DIR / f"system_health_audit_{TIMESTAMP_STR}.md"

audit_results = {
    "timestamp": datetime.datetime.now().isoformat(),
    "host_ip": "127.0.0.1",
    "services": {},
    "endpoints": {},
    "database": {},
    "browser_tests": {},
    "overall_status": "PENDING",
}


def log(msg, level="INFO"):
    entry = f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] [{level}] {msg}"
    print(entry)
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(entry + "\n")


def check_tcp_port(host, port, timeout=3.0):
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except Exception:
        return False


def http_get(url, timeout=10.0):
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    req = urllib.request.Request(
        url,
        headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) DSCons-HealthChecker/1.0"
        },
    )
    start = time.time()
    try:
        with urllib.request.urlopen(req, timeout=timeout, context=ctx) as response:
            latency_ms = round((time.time() - start) * 1000, 2)
            content = response.read().decode("utf-8", errors="ignore")
            return {
                "status_code": response.status,
                "latency_ms": latency_ms,
                "content_length": len(content),
                "headers": dict(response.getheaders()),
                "body_preview": content[:300].replace("\n", " ").strip(),
                "error": None,
            }
    except urllib.error.HTTPError as e:
        latency_ms = round((time.time() - start) * 1000, 2)
        try:
            content = e.read().decode("utf-8", errors="ignore")
        except Exception:
            content = ""
        return {
            "status_code": e.code,
            "latency_ms": latency_ms,
            "content_length": len(content),
            "headers": dict(e.headers) if hasattr(e, "headers") else {},
            "body_preview": content[:300].replace("\n", " ").strip(),
            "error": str(e),
        }
    except Exception as e:
        latency_ms = round((time.time() - start) * 1000, 2)
        return {
            "status_code": 0,
            "latency_ms": latency_ms,
            "content_length": 0,
            "headers": {},
            "body_preview": "",
            "error": str(e),
        }


def run_diagnostics():
    log("=== BẮT ĐẦU QUY TRÌNH KIỂM TRA CHẨN ĐOÁN TOÀN DIỆN HỆ THỐNG ===")

    # 1. Check Infrastructure Ports
    log("--- 1. Kiểm tra Ports & Dịch vụ Nền tảng ---")
    ports_to_check = {
        "FastAPI Backend (Port 8000)": ("127.0.0.1", 8000),
        "PostgreSQL DB (Port 5432)": ("127.0.0.1", 5432),
        "OpenSSH Server (Port 22)": ("127.0.0.1", 22),
        "RDP Server (Port 3389)": ("127.0.0.1", 3389),
        "LMStudio Local (Port 1234)": ("127.0.0.1", 1234),
    }
    for name, (h, p) in ports_to_check.items():
        is_open = check_tcp_port(h, p)
        audit_results["services"][name] = {"host": h, "port": p, "is_open": is_open}
        log(f"Service '{name}': {'[ONLINE]' if is_open else '[OFFLINE]'}")

    # 2. Check Tailscale Status
    log("--- 2. Kiểm tra Mạng Lưới Tailscale Mesh ---")
    try:
        ts_output = subprocess.check_output(
            ["tailscale", "status"], text=True, stderr=subprocess.STDOUT
        )
        audit_results["services"]["Tailscale"] = {
            "status": "ONLINE",
            "output": ts_output.strip().split("\n"),
        }
        log(f"Tailscale Status: Đang hoạt động với các node:\n{ts_output.strip()}")
    except Exception as e:
        audit_results["services"]["Tailscale"] = {"status": "ERROR", "error": str(e)}
        log(f"Tailscale Status Error: {e}", level="WARN")

    # 3. Check Cloudflare Tunnel
    log("--- 3. Kiểm tra Cloudflare Tunnel (dscons-erp) ---")
    try:
        cf_info = subprocess.check_output(
            ["cloudflared", "tunnel", "info", "dscons-erp"],
            text=True,
            stderr=subprocess.STDOUT,
        )
        audit_results["services"]["Cloudflare_Tunnel"] = {
            "status": "ACTIVE",
            "info": cf_info.strip(),
        }
        log(f"Cloudflare Tunnel Info:\n{cf_info.strip()}")
    except Exception as e:
        audit_results["services"]["Cloudflare_Tunnel"] = {
            "status": "ERROR",
            "error": str(e),
        }
        log(f"Cloudflare Tunnel Error: {e}", level="WARN")

    # 4. Check PostgreSQL Database Connectivity
    log("--- 4. Kiểm tra Kết Nối Database PostgreSQL ---")
    try:
        sys.path.insert(0, str(BASE_DIR))
        from psycopg import connect

        from app.core.settings import get_settings

        settings = get_settings()

        db_url = (
            settings.database_url
            or "postgresql://postgres:postgres@localhost:5432/dscons_erp"
        )
        with connect(db_url, connect_timeout=3) as conn:
            with conn.cursor() as cur:
                cur.execute(
                    "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public';"
                )
                row = cur.fetchone()
                table_count = row[0] if row else 0
                audit_results["database"] = {
                    "status": "HEALTHY",
                    "table_count": table_count,
                    "db_url_masked": db_url.split("@")[-1]
                    if "@" in db_url
                    else "local",
                }
                log(
                    f"PostgreSQL Database: KẾT NỐI THÀNH CÔNG! Số lượng bảng: {table_count}"
                )
    except Exception as e:
        audit_results["database"] = {"status": "ERROR", "error": str(e)}
        log(f"PostgreSQL Database Check Error: {e}", level="WARN")

    # 5. Check Local FastAPI Endpoints
    log("--- 5. Kiểm tra Endpoints Nội Bộ (Localhost:8000) ---")
    local_endpoints = [
        "http://127.0.0.1:8000/",
        "http://127.0.0.1:8000/health",
        "http://127.0.0.1:8000/docs",
        "http://127.0.0.1:8000/dashboard",
        "http://127.0.0.1:8000/projects",
        "http://127.0.0.1:8000/dashboard/projects",
        "http://127.0.0.1:8000/readiness",
        "http://127.0.0.1:8000/dashboard/readiness",
        "http://127.0.0.1:8000/employees",
        "http://127.0.0.1:8000/dashboard/employees",
        "http://127.0.0.1:8000/equipment",
        "http://127.0.0.1:8000/dashboard/equipment",
        "http://127.0.0.1:8000/invoices",
        "http://127.0.0.1:8000/dashboard/invoices",
        "http://127.0.0.1:8000/documents",
        "http://127.0.0.1:8000/dashboard/documents",
        "http://127.0.0.1:8000/partners",
        "http://127.0.0.1:8000/dashboard/partners",
        "http://127.0.0.1:8000/war-room",
        "http://127.0.0.1:8000/agent-models",
    ]
    for url in local_endpoints:
        res = http_get(url)
        audit_results["endpoints"][url] = res
        status_tag = (
            f"[{res['status_code']}]"
            if res["status_code"] == 200
            else f"[STATUS {res['status_code']}]"
        )
        log(f"Local {url} -> {status_tag} in {res['latency_ms']}ms")

    # 6. Check Public Production Website & ERP Domain Endpoints
    log(
        "--- 6. Kiểm tra Public Domain (dinhsonconstruction.com & erp.dinhsonconstruction.com) ---"
    )
    public_endpoints = [
        "https://dinhsonconstruction.com",
        "https://dinhsonconstruction.com/health",
        "https://dinhsonconstruction.com/docs",
        "https://dinhsonconstruction.com/dashboard",
        "https://dinhsonconstruction.com/projects",
        "https://dinhsonconstruction.com/dashboard/projects",
        "https://dinhsonconstruction.com/readiness",
        "https://dinhsonconstruction.com/dashboard/readiness",
        "https://dinhsonconstruction.com/employees",
        "https://dinhsonconstruction.com/equipment",
        "https://dinhsonconstruction.com/invoices",
        "https://dinhsonconstruction.com/documents",
        "https://dinhsonconstruction.com/partners",
        "https://dinhsonconstruction.com/war-room",
        "https://dinhsonconstruction.com/agent-models",
        "https://erp.dinhsonconstruction.com",
        "https://erp.dinhsonconstruction.com/dashboard",
        "https://erp.dinhsonconstruction.com/projects",
        "https://erp.dinhsonconstruction.com/readiness",
        "https://erp.dinhsonconstruction.com/invoices",
    ]

    all_public_ok = True
    for url in public_endpoints:
        res = http_get(url)
        audit_results["endpoints"][url] = res
        if res["status_code"] != 200:
            all_public_ok = False
            log(
                f"PUBLIC {url} -> [LỖI {res['status_code']}] (Error: {res['error']})",
                level="ERROR",
            )
        else:
            log(
                f"PUBLIC {url} -> [200 OK] ({res['latency_ms']}ms, {res['content_length']} bytes)"
            )

    # 7. Playwright Real Browser E2E Automation Verification
    log("--- 7. Kiểm tra Tương tác Thực tế trên Trình duyệt (Playwright) ---")
    try:
        from playwright.sync_api import sync_playwright

        with sync_playwright() as p:
            browser = p.chromium.launch(headless=True)
            page = browser.new_page()

            # 7.1 Verify Landing Page
            t0 = time.time()
            page.goto(
                "https://dinhsonconstruction.com",
                wait_until="domcontentloaded",
                timeout=15000,
            )
            page.wait_for_timeout(1000)
            title = page.title()
            landing_shot = SNAPSHOTS_DIR / f"audit_landing_{TIMESTAMP_STR}.png"
            page.screenshot(path=str(landing_shot), full_page=False)
            try:
                shutil.copy(landing_shot, ARTIFACT_DIR / "audit_landing_latest.png")
            except Exception:
                pass
            audit_results["browser_tests"]["landing_page"] = {
                "title": title,
                "url": page.url,
                "screenshot": str(landing_shot),
                "render_time_ms": round((time.time() - t0) * 1000, 2),
            }
            log(
                f"Playwright: Đã render Landing Page thành công: '{title}' -> Chụp snapshot: {landing_shot.name}"
            )

            # 7.2 Verify ERP Dashboard
            t0 = time.time()
            page.goto(
                "https://dinhsonconstruction.com/dashboard",
                wait_until="domcontentloaded",
                timeout=15000,
            )
            page.wait_for_timeout(1000)
            dash_title = page.title()
            dash_shot = SNAPSHOTS_DIR / f"audit_dashboard_{TIMESTAMP_STR}.png"
            page.screenshot(path=str(dash_shot), full_page=False)
            try:
                shutil.copy(dash_shot, ARTIFACT_DIR / "audit_dashboard_latest.png")
            except Exception:
                pass
            audit_results["browser_tests"]["dashboard_page"] = {
                "title": dash_title,
                "url": page.url,
                "screenshot": str(dash_shot),
                "render_time_ms": round((time.time() - t0) * 1000, 2),
            }
            log(
                f"Playwright: Đã render Dashboard thành công: '{dash_title}' -> Chụp snapshot: {dash_shot.name}"
            )

            # 7.3 Verify Projects & WBS
            t0 = time.time()
            page.goto(
                "https://dinhsonconstruction.com/projects",
                wait_until="domcontentloaded",
                timeout=15000,
            )
            page.wait_for_timeout(1000)
            proj_title = page.title()
            proj_shot = SNAPSHOTS_DIR / f"audit_projects_{TIMESTAMP_STR}.png"
            page.screenshot(path=str(proj_shot), full_page=False)
            try:
                shutil.copy(proj_shot, ARTIFACT_DIR / "audit_projects_latest.png")
            except Exception:
                pass
            audit_results["browser_tests"]["projects_page"] = {
                "title": proj_title,
                "url": page.url,
                "screenshot": str(proj_shot),
                "render_time_ms": round((time.time() - t0) * 1000, 2),
            }
            log(
                f"Playwright: Đã render Projects Page thành công: '{proj_title}' -> Chụp snapshot: {proj_shot.name}"
            )

            browser.close()
            audit_results["browser_tests"]["status"] = "PASSED"
    except Exception as e:
        audit_results["browser_tests"]["status"] = "ERROR"
        audit_results["browser_tests"]["error"] = str(e)
        log(f"Playwright Browser Verification Error: {e}", level="WARN")

    # 8. Overall Status Evaluation
    if (
        all_public_ok
        and audit_results["services"]["FastAPI Backend (Port 8000)"]["is_open"]
    ):
        audit_results["overall_status"] = "HEALTHY"
        log(
            "=== KẾT QUẢ TỔNG QUAN: TẤT CẢ CÁC DỊCH VỤ VÀ WEBSITE ĐANG HOẠT ĐỘNG HOÀN HẢO! ==="
        )
    else:
        audit_results["overall_status"] = "DEGRADED"
        log(
            "=== KẾT QUẢ TỔNG QUAN: PHÁT HIỆN DỊCH VỤ CHƯA HOÀN HẢO HOẶC CẦN SỬA CHỮA ===",
            level="WARN",
        )

    # 9. Generate Markdown Audit Report
    generate_markdown_report()


def generate_markdown_report():
    md = []
    md.append(
        "# BÁO CÁO KIỂM TRA & GIÁM SÁT HỆ THỐNG ERP DSCons (dinhsonconstruction.com)"
    )
    md.append(f"\n- **Thời gian thực hiện:** `{audit_results['timestamp']}`")
    md.append(f"- **Trạng thái tổng thể:** `{audit_results['overall_status']}`")
    md.append(f"- **File Nhật ký Truy vết:** `{LOG_FILE}`\n")

    md.append("## 1. Trạng Thái Cổng Mạng & Dịch Vụ Nền Tảng (Core Services)")
    md.append("| Dịch vụ / Cổng | Địa chỉ | Port | Trạng thái |")
    md.append("| :--- | :--- | :--- | :--- |")
    for name, s in audit_results["services"].items():
        if "port" in s:
            status_badge = "✅ ONLINE" if s["is_open"] else "❌ OFFLINE"
            md.append(
                f"| **{name}** | `{s['host']}` | `{s['port']}` | {status_badge} |"
            )
        elif "status" in s:
            status_badge = (
                "✅ " + s["status"]
                if s["status"] in ["ACTIVE", "ONLINE"]
                else "⚠️ " + s["status"]
            )
            md.append(f"| **{name}** | N/A | N/A | {status_badge} |")

    md.append("\n## 2. Trạng Thái Cơ Sở Dữ Liệu PostgreSQL")
    db = audit_results.get("database", {})
    if db.get("status") == "HEALTHY":
        md.append("- **Trạng thái:** ✅ HEALTHY (Kết nối trực tiếp thành công)")
        md.append(
            f"- **Số lượng Bảng (Tables):** `{db.get('table_count')}` bảng đã khởi tạo"
        )
    else:
        md.append(f"- **Trạng thái:** ❌ {db.get('status')}")
        md.append(f"- **Chi tiết lỗi:** `{db.get('error')}`")

    md.append("\n## 3. Kiểm Tra Kết Nối Mạng Lưới Public Endpoints (Production)")
    md.append("| Endpoint URL | HTTP Status | Phản hồi (ms) | Dung lượng (bytes) |")
    md.append("| :--- | :--- | :--- | :--- |")
    for url, res in audit_results["endpoints"].items():
        if "dinhsonconstruction.com" in url:
            status_str = (
                f"✅ {res['status_code']} OK"
                if res["status_code"] == 200
                else f"❌ {res['status_code']} ERROR"
            )
            md.append(
                f"| `{url}` | {status_str} | `{res['latency_ms']} ms` | `{res['content_length']} B` |"
            )

    md.append(
        "\n## 4. Kiểm Tra Tương Tác Trình Duyệt Thực Tế (Playwright Visual Verification)"
    )
    bw = audit_results.get("browser_tests", {})
    if bw.get("status") == "PASSED":
        md.append("- **Kết quả Playwright:** ✅ PASSED 100%")
        for page_key in ["landing_page", "dashboard_page", "projects_page"]:
            if page_key in bw:
                info = bw[page_key]
                md.append(
                    f"  - **{page_key.replace('_', ' ').title()}:** Tiêu đề `{info['title']}` ({info['render_time_ms']} ms) - Snapshot: `{info['screenshot']}`"
                )
    else:
        md.append(f"- **Kết quả Playwright:** ⚠️ {bw.get('status')} - {bw.get('error')}")

    md.append("\n## 5. Quy Trình Tự Động Khắc Phục Lỗi (Self-Healing Protocol)")
    md.append("Nếu bất kỳ dịch vụ nào gặp sự cố, quy trình xử lý tự động bao gồm:")
    md.append(
        "1. **Backend FastAPI Offline:** Tự động kích hoạt lại process qua `start_services.ps1` hoặc `uvicorn app.main:app`."
    )
    md.append(
        "2. **Cloudflare Tunnel Ngắt kết nối:** Tự động gọi `cloudflared tunnel run dscons-erp` nạp lại cấu hình edge."
    )
    md.append(
        "3. **OpenSSH Port 22 Closed:** Tự động chạy lệnh kích hoạt `sshd` Service."
    )
    md.append(
        "4. **PostgreSQL Service:** Tự động kiểm tra và restart service `postgresql-x64-16`."
    )

    with open(REPORT_FILE, "w", encoding="utf-8") as f:
        f.write("\n".join(md))

    log(f"Báo cáo Markdown đã được xuất thành công: {REPORT_FILE}")


if __name__ == "__main__":
    run_diagnostics()
