"""
Tests for Phase 100: THE GRAND ORCHESTRATOR.
"""

import json
import time
from datetime import datetime, timezone
from pathlib import Path

import pytest


@pytest.fixture(autouse=True)
def _isolate(tmp_path, monkeypatch):
    """Redirect all platform storage to tmp_path."""
    platform = tmp_path / "platform"
    platform.mkdir(parents=True, exist_ok=True)
    # Create core dirs that orchestrator expects
    for d in ("channels", "sessions", "cursors", "tasks", "profiles",
              "lifecycle", "costs", "incidents", "sla", "events"):
        (tmp_path / d).mkdir(parents=True, exist_ok=True)

    import brynq.server as srv
    monkeypatch.setattr(srv, "BROKER_DIR", tmp_path)

    import brynq.platform_orchestrator as po
    monkeypatch.setattr(po, "BROKER_DIR", tmp_path)
    monkeypatch.setattr(po, "PLATFORM_DIR", platform)
    monkeypatch.setattr(po, "BOOT_LOG_FILE", platform / "boot_log.jsonl")
    monkeypatch.setattr(po, "STATUS_FILE", platform / "status.json")
    monkeypatch.setattr(po, "_boot_time", None)


# ── Boot ──────────────────────────────────────────────────────────────────


class TestBoot:
    def test_boot_returns_report(self):
        from brynq.platform_orchestrator import boot
        report = boot()
        assert report["status"] == "operational"
        assert "boot_id" in report
        assert report["elapsed_seconds"] >= 0

    def test_boot_creates_directories(self, tmp_path):
        from brynq.platform_orchestrator import boot
        boot()
        for d in ("channels", "sessions", "tasks", "lifecycle", "costs",
                   "incidents", "sla", "platform"):
            assert (tmp_path / d).exists()

    def test_boot_logs_event(self, tmp_path):
        from brynq.platform_orchestrator import boot
        boot()
        log_file = tmp_path / "platform" / "boot_log.jsonl"
        assert log_file.exists()
        lines = log_file.read_text("utf-8").strip().splitlines()
        assert len(lines) >= 1
        entry = json.loads(lines[0])
        assert entry["status"] == "operational"

    def test_boot_writes_status_file(self, tmp_path):
        from brynq.platform_orchestrator import boot
        boot()
        status = json.loads((tmp_path / "platform" / "status.json").read_text("utf-8"))
        assert status["status"] == "operational"

    def test_boot_counts_modules(self):
        from brynq.platform_orchestrator import boot
        report = boot()
        assert report["modules_found"] > 0


# ── Platform Status ───────────────────────────────────────────────────────


class TestPlatformStatus:
    def test_status_after_boot(self):
        from brynq.platform_orchestrator import boot, get_platform_status
        boot()
        status = get_platform_status()
        assert status["status"] == "operational"
        assert status["health_score"] <= 100
        assert status["modules_loaded"] > 0
        assert status["version"] == "1.0.0"

    def test_status_includes_uptime(self):
        from brynq.platform_orchestrator import boot, get_platform_status
        boot()
        status = get_platform_status()
        assert status["uptime_seconds"] >= 0

    def test_status_without_boot(self):
        from brynq.platform_orchestrator import get_platform_status
        status = get_platform_status()
        assert status["uptime_seconds"] == 0

    def test_status_counts_agents(self, tmp_path):
        from brynq.platform_orchestrator import boot, get_platform_status
        boot()
        agents_dir = tmp_path / "lifecycle" / "agents"
        agents_dir.mkdir(parents=True, exist_ok=True)
        for i in range(3):
            (agents_dir / f"agent-{i}.json").write_text("{}")
        status = get_platform_status()
        assert status["active_agents"] == 3

    def test_status_counts_sessions(self, tmp_path):
        from brynq.platform_orchestrator import boot, get_platform_status
        boot()
        for i in range(2):
            (tmp_path / "sessions" / f"s{i}.json").write_text("{}")
        status = get_platform_status()
        assert status["active_sessions"] == 2


# ── Module Inventory ──────────────────────────────────────────────────────


class TestModuleInventory:
    def test_inventory_lists_modules(self):
        from brynq.platform_orchestrator import get_module_inventory
        modules = get_module_inventory()
        assert len(modules) > 0
        names = [m["name"] for m in modules]
        assert "platform_orchestrator" in names

    def test_inventory_has_line_counts(self):
        from brynq.platform_orchestrator import get_module_inventory
        modules = get_module_inventory()
        for m in modules:
            assert "lines" in m
            assert m["lines"] > 0

    def test_inventory_has_test_status(self):
        from brynq.platform_orchestrator import get_module_inventory
        modules = get_module_inventory()
        for m in modules:
            assert "has_tests" in m
            assert isinstance(m["has_tests"], bool)


# ── Diagnostics ───────────────────────────────────────────────────────────


class TestDiagnostics:
    def test_diagnostics_after_boot(self):
        from brynq.platform_orchestrator import boot, run_full_diagnostics
        boot()
        diag = run_full_diagnostics()
        assert diag["overall"] in ("healthy", "degraded")
        assert diag["checks_total"] > 0
        assert diag["checks_passed"] <= diag["checks_total"]

    def test_diagnostics_checks_directories(self, tmp_path):
        from brynq.platform_orchestrator import boot, run_full_diagnostics
        boot()
        diag = run_full_diagnostics()
        check_names = [c["check"] for c in diag["checks"]]
        assert "directory_channels" in check_names
        assert "directory_tasks" in check_names

    def test_diagnostics_checks_boot_log(self):
        from brynq.platform_orchestrator import boot, run_full_diagnostics
        boot()
        diag = run_full_diagnostics()
        boot_check = [c for c in diag["checks"] if c["check"] == "boot_log"]
        assert len(boot_check) == 1
        assert boot_check[0]["ok"] is True

    def test_diagnostics_without_boot(self):
        from brynq.platform_orchestrator import run_full_diagnostics
        diag = run_full_diagnostics()
        boot_check = [c for c in diag["checks"] if c["check"] == "boot_log"]
        assert len(boot_check) == 1
        assert boot_check[0]["ok"] is False


# ── Platform Summary ──────────────────────────────────────────────────────


class TestPlatformSummary:
    def test_summary_is_string(self):
        from brynq.platform_orchestrator import boot, get_platform_summary
        boot()
        summary = get_platform_summary()
        assert isinstance(summary, str)
        assert "Brynq" in summary
        assert "Synapse" in summary

    def test_summary_includes_version(self):
        from brynq.platform_orchestrator import boot, get_platform_summary
        boot()
        summary = get_platform_summary()
        assert "1.0.0" in summary

    def test_summary_includes_health(self):
        from brynq.platform_orchestrator import boot, get_platform_summary
        boot()
        summary = get_platform_summary()
        assert "health score" in summary.lower()


# ── Version ───────────────────────────────────────────────────────────────


class TestVersion:
    def test_version_info(self):
        from brynq.platform_orchestrator import get_version
        info = get_version()
        assert info["version"] == "1.0.0"
        assert info["codename"] == "Synapse"
        assert info["phase"] == 100

    def test_version_has_module(self):
        from brynq.platform_orchestrator import get_version
        assert get_version()["python_module"] == "brynq"


# ── Shutdown ──────────────────────────────────────────────────────────────


class TestShutdown:
    def test_shutdown_returns_event(self):
        from brynq.platform_orchestrator import boot, shutdown
        boot()
        event = shutdown("maintenance")
        assert event["event"] == "shutdown"
        assert event["reason"] == "maintenance"

    def test_shutdown_logs_event(self, tmp_path):
        from brynq.platform_orchestrator import boot, shutdown
        boot()
        shutdown("test")
        log_file = tmp_path / "platform" / "boot_log.jsonl"
        lines = log_file.read_text("utf-8").strip().splitlines()
        last = json.loads(lines[-1])
        assert last["event"] == "shutdown"

    def test_shutdown_writes_status(self, tmp_path):
        from brynq.platform_orchestrator import boot, shutdown
        boot()
        shutdown("done")
        status = json.loads((tmp_path / "platform" / "status.json").read_text("utf-8"))
        assert status["status"] == "shutdown"

    def test_shutdown_default_reason(self):
        from brynq.platform_orchestrator import boot, shutdown
        boot()
        event = shutdown()
        assert event["reason"] == "graceful shutdown"

    def test_shutdown_records_uptime(self):
        from brynq.platform_orchestrator import boot, shutdown
        boot()
        event = shutdown()
        assert event["uptime_seconds"] >= 0

    def test_shutdown_without_boot(self):
        from brynq.platform_orchestrator import shutdown
        event = shutdown("cold shutdown")
        assert event["uptime_seconds"] == 0
