#!/usr/bin/env python3
"""Probe read-only Argus KB diagnostics for current approved-proposal state."""

from __future__ import annotations

import argparse
import base64
import json
import urllib.error
import urllib.request
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Callable
from urllib.parse import urljoin

DEFAULT_BASE_URL = "http://77.42.65.182:8081"
REPORT_DIR = Path("docs/reports/leo-working-state-20260709")
DEFAULT_OUT = REPORT_DIR / "argus-kb-state-current.json"
DEFAULT_MARKDOWN_OUT = REPORT_DIR / "argus-kb-state-current.md"


FetchJson = Callable[[str, int], dict[str, Any]]


def fetch_json(url: str, timeout: int) -> dict[str, Any]:
    request = urllib.request.Request(url, headers={"Accept": "application/json"})
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:  # noqa: S310 - operator-supplied URL
            return json.loads(response.read().decode("utf-8"))
    except (urllib.error.URLError, TimeoutError, json.JSONDecodeError) as exc:
        return {"_fetch_error": str(exc)}


def endpoint(base_url: str, path: str) -> str:
    return urljoin(base_url.rstrip("/") + "/", path.lstrip("/"))


def decode_supplied_json(value: str | None) -> dict[str, Any] | None:
    if not value:
        return None
    try:
        return json.loads(base64.b64decode(value, validate=True).decode("utf-8"))
    except Exception as exc:  # noqa: BLE001 - retained as a structured fetch error
        return {"_fetch_error": f"failed to parse supplied base64 JSON: {exc}"}


def supplied_payloads(args: argparse.Namespace) -> dict[str, dict[str, Any] | None]:
    return {
        "kb_proposals": decode_supplied_json(args.kb_proposals_json_base64),
        "vital_signs": decode_supplied_json(args.vital_signs_json_base64),
        "metrics": decode_supplied_json(args.metrics_json_base64),
    }


def proposal_summary(kb_proposals: dict[str, Any]) -> dict[str, Any]:
    packets = kb_proposals.get("packets") if isinstance(kb_proposals.get("packets"), list) else []
    return {
        "generated_at": kb_proposals.get("generated_at"),
        "filters": kb_proposals.get("filters"),
        "total": kb_proposals.get("total"),
        "status_counts": kb_proposals.get("status_counts") or {},
        "review_state_counts": kb_proposals.get("review_state_counts") or {},
        "worker_applyable_count": kb_proposals.get("worker_applyable_count"),
        "read_only": kb_proposals.get("read_only"),
        "proposal_ids": [packet.get("proposal_id") for packet in packets],
        "proposal_review_states": {
            packet.get("proposal_id"): packet.get("review_state") for packet in packets if packet.get("proposal_id")
        },
        "proposal_applyability": {
            packet.get("proposal_id"): {
                "worker_applyable": packet.get("worker_applyable"),
                "has_apply_payload": packet.get("has_apply_payload"),
                "next_admin_action": packet.get("next_admin_action"),
            }
            for packet in packets
            if packet.get("proposal_id")
        },
    }


def collect(args: argparse.Namespace, *, fetcher: FetchJson = fetch_json) -> dict[str, Any]:
    urls = {
        "kb_proposals": endpoint(args.base_url, "/api/kb-proposals"),
        "vital_signs": endpoint(args.base_url, "/api/vital-signs"),
        "metrics": endpoint(args.base_url, "/api/metrics"),
    }
    supplied = supplied_payloads(args)
    raw = {name: payload if payload is not None else fetcher(urls[name], args.timeout) for name, payload in supplied.items()}
    fetch_sources = {name: "supplied_base64_json" if payload is not None else "urllib" for name, payload in supplied.items()}
    proposals = proposal_summary(raw["kb_proposals"])
    proposal_total = proposals.get("total")
    review_state_counts = proposals.get("review_state_counts") or {}
    status_counts = proposals.get("status_counts") or {}
    checks = {
        "http_readback_ok": all("_fetch_error" not in payload for payload in raw.values()),
        "approved_proposals_visible": isinstance(proposal_total, int)
        and proposal_total > 0
        and status_counts.get("approved") == proposal_total,
        "approved_need_apply_payload": isinstance(proposal_total, int)
        and review_state_counts.get("approved_needs_apply_payload") == proposal_total,
        "no_worker_applyable_approved_proposals": proposals.get("worker_applyable_count") == 0,
        "kb_proposals_endpoint_read_only": proposals.get("read_only") is True,
    }
    return {
        "generated_at_utc": datetime.now(timezone.utc).isoformat(),
        "mode": "argus_kb_state_readonly_http_probe",
        "base_url": args.base_url,
        "urls": urls,
        "fetch_sources": fetch_sources,
        "status": "pass" if all(checks.values()) else "fail",
        "checks": checks,
        "summary": {
            "proposals": proposals,
            "vital_signs": {
                "claim_index_status": raw["vital_signs"].get("claim_index_status"),
                "review_throughput": raw["vital_signs"].get("review_throughput"),
                "funnel": raw["vital_signs"].get("funnel"),
                "queue_staleness": raw["vital_signs"].get("queue_staleness"),
            },
            "metrics": {
                "status_map": raw["metrics"].get("status_map"),
                "source_map": raw["metrics"].get("source_map"),
                "breakers": raw["metrics"].get("breakers"),
            },
        },
        "raw": raw,
        "claim_ceiling": (
            "This is public Argus HTTP diagnostics evidence only. It proves the diagnostics surface can see "
            "approved KB proposals and their applyability state; it does not prove Docker/Postgres row counts, "
            "gateway systemd state, Telegram-visible reply quality, or production apply execution."
        ),
    }


def write_json(path: Path, data: dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8")


def write_markdown(path: Path, data: dict[str, Any]) -> None:
    proposals = data["summary"]["proposals"]
    lines = [
        "# Argus KB State Probe",
        "",
        f"Generated UTC: `{data['generated_at_utc']}`",
        f"Mode: `{data['mode']}`",
        f"Status: `{data['status']}`",
        f"Base URL: `{data['base_url']}`",
        "",
        "## Fetch Sources",
        "",
    ]
    lines.extend(f"- `{key}`: `{value}`" for key, value in sorted(data["fetch_sources"].items()))
    lines.extend(
        [
            "",
            "## Checks",
            "",
        ]
    )
    lines.extend(f"- `{key}`: `{value}`" for key, value in sorted(data["checks"].items()))
    lines.extend(
        [
            "",
            "## Approved Proposal State",
            "",
            f"- Total: `{proposals.get('total')}`",
            f"- Status counts: `{json.dumps(proposals.get('status_counts'), sort_keys=True)}`",
            f"- Review state counts: `{json.dumps(proposals.get('review_state_counts'), sort_keys=True)}`",
            f"- Worker-applyable count: `{proposals.get('worker_applyable_count')}`",
            f"- Read-only endpoint: `{proposals.get('read_only')}`",
            "",
            "## Proposal IDs",
            "",
        ]
    )
    lines.extend(f"- `{proposal_id}`" for proposal_id in proposals.get("proposal_ids") or [])
    lines.extend(["", "## Claim Ceiling", "", data["claim_ceiling"], ""])
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text("\n".join(lines), encoding="utf-8")


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
    parser.add_argument("--timeout", type=int, default=10)
    parser.add_argument("--kb-proposals-json-base64")
    parser.add_argument("--vital-signs-json-base64")
    parser.add_argument("--metrics-json-base64")
    parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
    parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT)
    return parser.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = parse_args(argv)
    data = collect(args)
    write_json(args.out, data)
    write_markdown(args.markdown_out, data)
    print(
        json.dumps(
            {
                "out": str(args.out),
                "markdown_out": str(args.markdown_out),
                "status": data["status"],
                "checks": data["checks"],
            },
            indent=2,
            sort_keys=True,
        )
    )
    return 0 if data["status"] == "pass" else 2


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