from __future__ import annotations

import json
import subprocess
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[3]


def read(path: str) -> str:
    return (ROOT / path).read_text(encoding="utf-8")


def test_reboot_p0_contract_covers_all_required_hosts_and_vmware_autostart() -> None:
    host_probe = read("scripts/reboot-recovery/reboot-auto-recovery-host-probe.sh")
    windows99 = read("scripts/reboot-recovery/windows99-vmware-autostart.ps1")

    for host in ["99", "110", "111", "112", "120", "121", "188"]:
        assert host in host_probe
    assert 'run_with_timeout "${TCP_CONNECT_TIMEOUT_SECONDS:-2}"' in host_probe
    assert "AWOOOI-Start-VMware-VMs" in windows99
    assert "NoAutoRebootWithLoggedOnUsers" in windows99
    assert "Host110Vmx" in windows99
    assert "Host111Vmx" in windows99
    assert "Host188Vmx" in windows99
    assert "Host120Vmx" in windows99
    assert "Host121Vmx" in windows99
    assert "Host112Vmx" in windows99
    assert "D:\\Documents\\Virtual Machines" in windows99
    assert "D:\\Downloads" in windows99
    assert '[string[]]$RequiredVmAliases = @("111", "188", "120", "121", "112")' in windows99
    assert "HOST111_VMWARE_TARGET=explicit_or_required" in windows99
    assert "VMWARE_AUTOSTART_VERIFY_READY" in windows99
    assert "WINDOWS_UPDATE_POLICY" in windows99
    assert "VM_POWER alias=$alias" in windows99
    assert "VM_ALREADY_RUNNING" in windows99


def test_reboot_p0_contract_has_maintenance_and_telegram_alerts() -> None:
    alerts = read("ops/monitoring/alerts-unified.yml")
    runbook = read("docs/runbooks/PUBLIC-MAINTENANCE-FALLBACK-RUNBOOK.md")
    snippet = read("ops/maintenance/nginx-502-maintenance-snippet.conf")
    probe = read("scripts/reboot-recovery/public-maintenance-fallback-probe.py")
    exporter = read("scripts/reboot-recovery/reboot-auto-recovery-slo-exporter.sh")

    for alert_name in [
        "HostRebootEventDetected",
        "RebootAutoRecoverySLOMissed",
        "RebootAutoRecoveryActiveBlocker",
        "RebootAutoRecoveryActiveBlockerMetricMissing",
        "PublicRouteServing5xxWithoutMaintenanceFallback",
        "BackupCoverageDomainStale",
    ]:
        assert alert_name in alerts
    assert "notification_type: TYPE-3" in alerts
    assert "proxy_intercept_errors on" in snippet
    assert "X-AWOOOI-Fallback" in snippet
    assert "502" in runbook
    assert "L0" in runbook
    assert "L1" in runbook
    assert "raw_5xx_without_fallback" in probe
    assert "public-maintenance-fallback.json" in exporter
    assert "--public-maintenance-file" in exporter
    assert "awoooi_public_route_raw_5xx_without_maintenance_fallback" in exporter
    assert "awoooi_reboot_auto_recovery_slo_active_blocker" in exporter
    assert 'blocker="{label(blocker)}"' in exporter
    assert "$labels.blocker" in alerts


def test_reboot_p0_contract_applies_l0_fallback_to_awoooi_nginx_sources() -> None:
    for path in [
        "ops/nginx/awoooi.wooo.work.conf",
        "k8s/nginx/awoooi-prod.conf",
    ]:
        conf = read(path)
        assert "proxy_intercept_errors on;" in conf
        assert "error_page 502 503 504 /__awoooi-maintenance.html;" in conf
        assert "location = /__awoooi-maintenance.html" in conf
        assert "root /var/www/maintenance;" in conf
        assert "try_files /maintenance.html =503;" in conf
        assert 'add_header Retry-After "120" always;' in conf
        assert 'add_header X-AWOOOI-Fallback "local-maintenance" always;' in conf
        assert "/50x.html" not in conf


def test_reboot_slo_scorecard_fails_closed_on_raw_public_502(tmp_path: Path) -> None:
    summary = tmp_path / "summary.txt"
    summary.write_text(
        "\n".join(
            [
                "SERVICE_GREEN=1",
                "PRODUCT_DATA_GREEN=1",
                "BACKUP_CORE_GREEN=1",
                "POST_START_BLOCKED=0",
                "HOST_188_SERVICE_GREEN=1",
            ]
        ),
        encoding="utf-8",
    )
    host_probe = tmp_path / "host-probe.txt"
    host_probe.write_text(
        "\n".join(
            f"HOST_BOOT alias={alias} host=192.168.0.{alias} reachable=1 uptime_seconds=120"
            for alias in ["99", "110", "111", "112", "120", "121", "188"]
        ),
        encoding="utf-8",
    )
    reboot_event = tmp_path / "reboot-event.json"
    reboot_event.write_text(
        json.dumps(
            {
                "reboot_detected": True,
                "all_required_hosts_observed": True,
                "all_required_hosts_in_reboot_window": True,
                "fresh_boot_hosts": ["99", "110", "111", "112", "120", "121", "188"],
                "missing_hosts": [],
                "unreachable_hosts": [],
                "target_seconds_remaining": 480,
                "recovery_deadline_status": "inside_target_window",
            }
        ),
        encoding="utf-8",
    )
    public_probe = tmp_path / "public-maintenance.json"
    public_probe.write_text(
        json.dumps(
            {
                "runtime_readback_present": True,
                "ready": False,
                "raw_5xx_without_fallback_count": 1,
                "route_unreachable_without_external_fallback_count": 0,
                "maintenance_fallback_route_count": 0,
                "raw_5xx_without_fallback_urls": ["https://awoooi.wooo.work/"],
                "blockers": ["public_route_raw_5xx_without_maintenance_fallback"],
                "routes": [
                    {
                        "url": "https://awoooi.wooo.work/",
                        "http_status": 502,
                        "status": "raw_5xx_without_maintenance_fallback",
                        "fallback_header": "",
                        "maintenance_body_detected": False,
                        "maintenance_fallback_serving": False,
                        "raw_5xx_without_fallback": True,
                    }
                ],
            }
        ),
        encoding="utf-8",
    )
    windows99 = tmp_path / "windows99-vmware.txt"
    windows99.write_text(
        "\n".join(
            [
                "VMRUN_PRESENT=1",
                "VMWARE_AUTOSTART_CONFIG_READY=1",
                "VMWARE_AUTOSTART_POWER_READY=1",
                "WINDOWS_UPDATE_NO_AUTO_REBOOT_READY=1",
                "VMWARE_AUTOSTART_VERIFY_READY=1",
                "VMWARE_SERVICE name=VMAuthdService present=1 status=Running startup_type=Automatic ok=1",
                "VMWARE_SERVICE name=VMnetDHCP present=1 status=Running startup_type=Automatic ok=1",
                "VMWARE_AUTOSTART_TASK name=AWOOOI-Start-VMware-VMs present=1 enabled=1 state=Ready trigger_count=1 action_count=1 ok=1",
                "WINDOWS_UPDATE_POLICY name=NoAutoRebootWithLoggedOnUsers value=1 expected=1 ok=1",
                *[
                    f"VMX alias={alias} path=D:\\Documents\\Virtual Machines\\{alias}\\{alias}.vmx present=1"
                    for alias in ["111", "112", "120", "121", "188"]
                ],
                *[
                    f"VM_POWER alias={alias} vmx_present=1 running=1"
                    for alias in ["111", "112", "120", "121", "188"]
                ],
            ]
        ),
        encoding="utf-8",
    )

    result = subprocess.run(
        [
            sys.executable,
            str(ROOT / "scripts/reboot-recovery/reboot-auto-recovery-slo-scorecard.py"),
            "--summary-file",
            str(summary),
            "--host-probe-file",
            str(host_probe),
            "--reboot-event-file",
            str(reboot_event),
            "--public-maintenance-file",
            str(public_probe),
            "--windows99-vmware-file",
            str(windows99),
        ],
        text=True,
        capture_output=True,
        check=True,
    )
    payload = json.loads(result.stdout)

    assert "public_route_raw_5xx_without_maintenance_fallback" in payload["active_blockers"]
    assert payload["required_checks"]["public_maintenance_fallback_runtime_ready"] is False
    assert payload["current_phase"] == "public_maintenance_fallback_blocked"
    assert payload["rollups"]["public_route_raw_5xx_without_fallback_count"] == 1


def test_backup_exporter_emits_domain_level_backup_coverage() -> None:
    exporter = read("scripts/ops/backup-health-textfile-exporter.py")

    assert "awoooi_backup_coverage_domain_expected_info" in exporter
    assert "awoooi_backup_coverage_domain_fresh" in exporter
    assert "gitea_repo_mirror_from_110" in exporter
    assert "/home/ollama/backup/110/gitea" in exporter
    for domain in ["host", "database", "website", "service", "package", "tool", "log"]:
        assert f'"{domain}"' in exporter


def test_backup_alerts_cover_188_gitea_mirror_subtree() -> None:
    alerts = read("ops/monitoring/alerts-unified.yml")

    assert 'awoooi_backup_coverage_domain_expected_info{host="188"}' in alerts
    assert "BackupCoverageDomainMetricMissing188" in alerts
    assert "awoooi_backup_coverage_domain_fresh == 0" in alerts
    assert "GiteaPrivateBundleRestoreDryRunMissing" in alerts
    assert "awoooi_gitea_bundle_sample_restore_dry_run_ok" in alerts


def test_gitea_repo_bundle_backup_is_non_interactive_and_manifested() -> None:
    script = read("scripts/backup/gitea-repo-bundle-backup.sh")
    restore_script = read("scripts/backup/gitea-bundle-sample-restore-dry-run.sh")

    assert "GIT_TERMINAL_PROMPT=0" in script
    assert "bundle create" in script
    assert "bundle verify" in script
    assert ".sha256" in script
    assert "manifest.tsv" in script
    assert "gitea dump" in script
    assert "does not replace `gitea dump`" in script
    assert "tokens or passwords" in script
    assert "git clone --mirror --quiet" in restore_script
    assert "fsck --connectivity-only" in restore_script
    assert "awoooi_gitea_bundle_sample_restore_dry_run_ok" in restore_script
    assert "never reads tokens" in restore_script
