# edited by glg
import importlib.util
import json
import sys
from pathlib import Path

import pytest


pytestmark = [pytest.mark.unit]


def _load_pipeline_module():
    repo_root = Path(__file__).resolve().parents[2]
    module_path = repo_root / "scripts" / "ops" / "run_dr_fleet_pipeline.py"
    spec = importlib.util.spec_from_file_location("run_dr_fleet_pipeline", module_path)
    module = importlib.util.module_from_spec(spec)
    assert spec and spec.loader
    spec.loader.exec_module(module)
    return module


def test_main_pipeline_lulus_saat_semua_stage_sehat(monkeypatch, tmp_path):
    module = _load_pipeline_module()
    captured = {}

    class _BackupStub:
        def __init__(self, backup_root):
            captured["backup_root"] = str(backup_root)

        def run_backup(self, source_paths, tag=""):
            captured["backup_source_files"] = list(source_paths or [])
            captured["backup_tag"] = str(tag)
            return {
                "manifest_path": str(tmp_path / "manifest.json"),
                "copied_files": [{"source": "x", "target": "y"}],
                "missing_files": [],
            }

        def prune_backups(self, keep_last=14, max_age_days=30):
            captured["prune_keep_last"] = int(keep_last)
            captured["prune_max_age_days"] = int(max_age_days)
            return {"deleted": [], "kept": []}

    class _RestoreStub:
        def __init__(self, work_root=""):
            captured["restore_work_root"] = str(work_root)

        def run_restore_drill(self, manifest_path, restore_root=""):
            captured["restore_manifest"] = str(manifest_path)
            captured["restore_root"] = str(restore_root)
            return {"ok": True, "report_path": str(tmp_path / "restore_report.json")}

    class _ReconcileStub:
        def __init__(self, db_path, stale_inprogress_seconds):
            captured["reconcile_db_path"] = str(db_path)
            captured["reconcile_stale_seconds"] = int(stale_inprogress_seconds)

        def run_reconciliation(self, retention_policy=None):
            captured["reconcile_retention_policy"] = retention_policy if isinstance(retention_policy, dict) else {}
            return {"outbox_dead": 0}

    class _FleetStub:
        def evaluate_wave_files(
            self,
            *,
            plan_file,
            wave_name,
            metrics_file,
            fail_threshold_pct=2.0,
            latency_threshold_ms=2000.0,
        ):
            captured["fleet_plan_file"] = str(plan_file)
            captured["fleet_wave_name"] = str(wave_name)
            captured["fleet_metrics_file"] = str(metrics_file)
            captured["fleet_fail_threshold_pct"] = float(fail_threshold_pct)
            captured["fleet_latency_threshold_ms"] = float(latency_threshold_ms)
            return {"healthy": True, "decision": "continue"}

    output_file = tmp_path / "ops_pipeline.json"
    monkeypatch.setattr(module, "DrBackupPolicyService", _BackupStub)
    monkeypatch.setattr(module, "DrRestoreDrillService", _RestoreStub)
    monkeypatch.setattr(module, "TransaksiEnterpriseControlService", _ReconcileStub)
    monkeypatch.setattr(module, "FleetRolloutOrchestratorService", _FleetStub)
    monkeypatch.setattr(
        sys,
        "argv",
        [
            "run_dr_fleet_pipeline.py",
            "--backup-root",
            str(tmp_path / "backups"),
            "--restore-root",
            str(tmp_path / "restore"),
            "--db-path",
            str(tmp_path / "pos.db"),
            "--run-reconciliation",
            "1",
            "--run-retention",
            "1",
            "--fleet-plan-file",
            str(tmp_path / "plan.json"),
            "--fleet-wave-name",
            "canary",
            "--fleet-metrics-file",
            str(tmp_path / "metrics.json"),
            "--output",
            str(output_file),
        ],
    )

    exit_code = module.main()

    assert int(exit_code) == 0
    assert str(captured.get("fleet_wave_name") or "") == "canary"
    assert int((captured.get("reconcile_retention_policy") or {}).get("limit") or 0) == 500
    payload = json.loads(output_file.read_text(encoding="utf-8"))
    assert bool(payload.get("ok")) is True
    assert bool((payload.get("checks") or {}).get("fleet_gate_ok")) is True


def test_main_pipeline_gagal_saat_outbox_dead_dan_fail_on_dead_aktif(monkeypatch, tmp_path):
    module = _load_pipeline_module()

    class _BackupStub:
        def __init__(self, backup_root):
            _ = backup_root

        def run_backup(self, source_paths, tag=""):
            _ = source_paths
            _ = tag
            return {
                "manifest_path": str(tmp_path / "manifest.json"),
                "copied_files": [{"source": "x", "target": "y"}],
                "missing_files": [],
            }

        def prune_backups(self, keep_last=14, max_age_days=30):
            _ = keep_last
            _ = max_age_days
            return {"deleted": [], "kept": []}

    class _RestoreStub:
        def __init__(self, work_root=""):
            _ = work_root

        def run_restore_drill(self, manifest_path, restore_root=""):
            _ = manifest_path
            _ = restore_root
            return {"ok": True}

    class _ReconcileStub:
        def __init__(self, db_path, stale_inprogress_seconds):
            _ = db_path
            _ = stale_inprogress_seconds

        def run_reconciliation(self, retention_policy=None):
            _ = retention_policy
            return {"outbox_dead": 2}

    output_file = tmp_path / "ops_pipeline_fail.json"
    monkeypatch.setattr(module, "DrBackupPolicyService", _BackupStub)
    monkeypatch.setattr(module, "DrRestoreDrillService", _RestoreStub)
    monkeypatch.setattr(module, "TransaksiEnterpriseControlService", _ReconcileStub)
    monkeypatch.setattr(
        sys,
        "argv",
        [
            "run_dr_fleet_pipeline.py",
            "--backup-root",
            str(tmp_path / "backups"),
            "--restore-root",
            str(tmp_path / "restore"),
            "--db-path",
            str(tmp_path / "pos.db"),
            "--run-reconciliation",
            "1",
            "--fail-on-dead",
            "1",
            "--output",
            str(output_file),
        ],
    )

    exit_code = module.main()

    assert int(exit_code) == 2
    payload = json.loads(output_file.read_text(encoding="utf-8"))
    assert bool(payload.get("ok")) is False
    assert bool((payload.get("checks") or {}).get("reconciliation_ok")) is False
