"""Log viewing and snapshot endpoints."""

from __future__ import annotations

import asyncio
import json
import platform
import shutil
import socket
import sys
from collections import deque
from datetime import datetime

from fastapi import APIRouter, HTTPException
from fastapi.responses import PlainTextResponse

from Project.Sanad.config import BASE_DIR, LOGS_DIR
from Project.Sanad.dashboard.routes._safe_io import safe_path_under

router = APIRouter()


def _list_logs_sync():
    LOGS_DIR.mkdir(parents=True, exist_ok=True)
    files = []
    for p in sorted(LOGS_DIR.glob("*.log*")):
        files.append({
            "name": p.name,
            "size_bytes": p.stat().st_size,
        })
    return files


@router.get("/")
async def list_logs():
    files = await asyncio.to_thread(_list_logs_sync)
    return {"logs_dir": str(LOGS_DIR), "files": files}


def _tail_sync(path, lines: int) -> list[str]:
    with open(path, "r", encoding="utf-8", errors="replace") as f:
        tail = deque(f, maxlen=lines)
    return [l.rstrip("\n") for l in tail]


@router.get("/tail/{filename}")
async def tail_log(filename: str, lines: int = 200):
    path = safe_path_under(LOGS_DIR, filename)
    if not path.exists():
        raise HTTPException(404, "File not found")
    lines_out = await asyncio.to_thread(_tail_sync, path, lines)
    return {"filename": path.name, "lines": lines_out}


def _snapshot_sync(ts: str):
    saved = []
    for p in LOGS_DIR.glob("*.log"):
        # Skip prior snapshots to avoid recursive growth
        if "_snapshot_" in p.stem:
            continue
        dest = LOGS_DIR / f"{p.stem}_snapshot_{ts}.log"
        shutil.copy2(p, dest)
        saved.append({"source": p.name, "snapshot": dest.name, "size_bytes": dest.stat().st_size})
    return saved


@router.post("/snapshot")
async def save_log_snapshot():
    """Save timestamped copy of all log files."""
    LOGS_DIR.mkdir(parents=True, exist_ok=True)
    ts = datetime.now().strftime("%Y%m%d_%H%M%S")
    saved = await asyncio.to_thread(_snapshot_sync, ts)
    return {"ok": True, "saved_at": ts, "snapshots": saved}


# ─────────────────────── full bundle (everything in one text blob) ───────────────────────

def _build_bundle_sync(lines_per_file: int, include_system: bool) -> str:
    """Build the full text bundle — header, subsystem status, all logs.

    Returns a single string safe to copy directly into a bug report.
    """
    out: list[str] = []
    ts = datetime.now().isoformat(timespec="seconds")
    out.append("=" * 72)
    out.append(f"SANAD LOG BUNDLE — {ts}")
    out.append("=" * 72)
    out.append(f"Hostname  : {socket.gethostname()}")
    out.append(f"Platform  : {platform.platform()}")
    out.append(f"Python    : {sys.version.split()[0]}")
    out.append(f"Executable: {sys.executable}")
    out.append(f"BASE_DIR  : {BASE_DIR}")
    out.append(f"LOGS_DIR  : {LOGS_DIR}")

    # Subsystems — pull live status from main.SUBSYSTEMS
    if include_system:
        out.append("")
        out.append("-" * 72)
        out.append("SUBSYSTEMS")
        out.append("-" * 72)
        try:
            from Project.Sanad.main import SUBSYSTEMS
        except Exception as exc:
            out.append(f"  could not import SUBSYSTEMS: {exc}")
            SUBSYSTEMS = {}

        for name in sorted(SUBSYSTEMS):
            comp = SUBSYSTEMS[name]
            if comp is None:
                out.append(f"  ✗ {name:15s} unavailable")
                continue
            status: dict = {}
            if hasattr(comp, "status") and callable(comp.status):
                try:
                    s = comp.status()
                    if isinstance(s, dict):
                        status = s
                    else:
                        status = {"raw": str(s)}
                except Exception as exc:
                    status = {"status_error": str(exc)}
            try:
                status_str = json.dumps(status, ensure_ascii=False, default=str)
            except Exception:
                status_str = str(status)
            out.append(f"  ✓ {name:15s} {status_str}")

        # Dashboard router load state
        out.append("")
        out.append("-" * 72)
        out.append("DASHBOARD ROUTERS")
        out.append("-" * 72)
        try:
            from Project.Sanad.dashboard.app import _loaded_routes, _failed_routes
            out.append(f"  loaded ({len(_loaded_routes)}): {', '.join(_loaded_routes)}")
            if _failed_routes:
                out.append(f"  failed ({len(_failed_routes)}):")
                for name, err in _failed_routes.items():
                    out.append(f"    - {name}: {err}")
            else:
                out.append("  failed (0): —")
        except Exception as exc:
            out.append(f"  could not read dashboard state: {exc}")

    # All log files — tail N lines each, skip snapshots
    out.append("")
    out.append("-" * 72)
    out.append(f"LOG FILES (last {lines_per_file} lines each)")
    out.append("-" * 72)

    LOGS_DIR.mkdir(parents=True, exist_ok=True)
    log_paths = sorted(LOGS_DIR.glob("*.log*"))
    files_included = 0
    for p in log_paths:
        if "_snapshot_" in p.stem:
            continue  # skip stale snapshots
        try:
            size = p.stat().st_size
        except OSError:
            size = 0
        out.append("")
        out.append(f"=== {p.name}  ({size} bytes) ===")
        try:
            with open(p, "r", encoding="utf-8", errors="replace") as f:
                tail = deque(f, maxlen=lines_per_file)
            for raw in tail:
                out.append(raw.rstrip("\n"))
            files_included += 1
        except OSError as exc:
            out.append(f"  <could not read: {exc}>")

    out.append("")
    out.append("=" * 72)
    out.append(f"END OF BUNDLE — {files_included} log file(s) included")
    out.append("=" * 72)
    return "\n".join(out)


@router.get("/bundle")
async def logs_bundle(lines: int = 1000, include_system: bool = True):
    """Return a single plain-text dump of everything useful for debugging.

    Includes:
      - Timestamp, hostname, platform, Python, BASE_DIR, LOGS_DIR
      - Live status of every subsystem in main.SUBSYSTEMS
      - Dashboard router load/fail state
      - Tail of every .log file in LOGS_DIR (configurable per-file limit)

    Response is `text/plain` so it's safe to copy straight to clipboard
    or pipe into a file. Intended use: dashboard "Copy All Logs" button
    and manual `curl ... > sanad_bundle.txt` debugging.
    """
    # Clamp lines to keep the payload sane
    lines = max(10, min(int(lines), 50000))
    text = await asyncio.to_thread(_build_bundle_sync, lines, include_system)
    return PlainTextResponse(
        text,
        headers={
            "Content-Disposition": (
                f'inline; filename="sanad_bundle_{datetime.now().strftime("%Y%m%d_%H%M%S")}.txt"'
            ),
        },
    )
