import json
import tempfile
import unittest
from pathlib import Path

from core.database import EventDatabase
from gui.adapters import (ConfigurationAdapter, DataAdapter, RelayAdapter, filter_rows,
                          format_timestamp, health_from_status, metadata_summary, validate_config)


def valid_config(output_path="C:/Logs/events.jsonl"):
    return {"Enabled": True, "AllowList": ["explorer.exe"], "WatchList": ["python.exe"],
            "AlertRules": {"HighRiskKeywords": ["-enc"], "MinSeverity": "low"},
            "Telemetry": {"Path": output_path, "PollIntervalSeconds": 2,
                          "HeartbeatIntervalSeconds": 30, "RetentionDays": 14}}


class FakeWrapper:
    def __init__(self): self.calls = []
    def status(self): self.calls.append("status"); return {"running": False}
    def start(self): self.calls.append("start"); return {"running": True, "pid": 5}
    def stop(self): self.calls.append("stop"); return {"running": False}


class TestGuiLogic(unittest.TestCase):
    def test_status_mapping(self):
        driver = {"running": True, "installed": True, "error": None}
        relay = {"running": True}
        self.assertEqual("Healthy", health_from_status(driver, relay, True, True))
        self.assertEqual("Degraded", health_from_status(driver, {"running": False}, True, True))
        self.assertEqual("Error", health_from_status(driver, {"running": False, "error": "failure"}, True, True))

    def test_formatting_and_filtering(self):
        self.assertNotEqual("—", format_timestamp("2026-08-14T12:00:00+00:00"))
        self.assertIn("pid", metadata_summary({"pid": 42}))
        rows = [{"process": "python.exe", "severity": "high"}, {"process": "explorer.exe", "severity": "info"}]
        self.assertEqual(1, len(filter_rows(rows, "python", severity="high")))
        self.assertEqual(2, len(filter_rows(rows, "", severity="All")))

    def test_config_validation_and_atomic_backup(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = Path(tmpdir) / "config.json"
            payload = valid_config(str(Path(tmpdir) / "events.jsonl"))
            path.write_text(json.dumps(payload), encoding="utf-8")
            adapter = ConfigurationAdapter(path)
            self.assertEqual([], validate_config(adapter.load()))
            changed = adapter.load(); changed["Telemetry"]["PollIntervalSeconds"] = 4
            backup = adapter.save(changed)
            self.assertTrue(backup.exists())
            self.assertEqual(4, json.loads(path.read_text(encoding="utf-8"))["Telemetry"]["PollIntervalSeconds"])
            changed["Telemetry"]["PollIntervalSeconds"] = 0
            with self.assertRaises(ValueError): adapter.save(changed)

    def test_relay_adapter_delegates_to_existing_wrapper(self):
        fake = FakeWrapper(); adapter = RelayAdapter(wrapper=fake)
        self.assertFalse(adapter.status()["running"]); self.assertTrue(adapter.start()["running"]); adapter.stop()
        self.assertEqual(["status", "start", "stop"], fake.calls)

    def test_database_adapter_and_jsonl_tolerance(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            root = Path(tmpdir); db_path = root / "events.db"; log_path = root / "events.jsonl"; config_path = root / "config.json"
            config_path.write_text(json.dumps(valid_config(str(log_path))), encoding="utf-8")
            db = EventDatabase(db_path)
            base = {"timestamp": "2026-08-14T12:00:00+00:00", "source": "relay_service", "severity": "high",
                    "confidence": 0, "hostname": None, "user": None, "parent_pid": None, "path": None,
                    "command_line": None, "sha256": None, "signer": None, "signed": None, "risk_score": 80,
                    "tags": [], "metadata": {}}
            db.insert_event({**base, "event_id": "start", "event_type": "process_started", "pid": 42, "process_name": "python.exe"})
            adapter = DataAdapter(db_path, config_path)
            self.assertEqual(1, adapter.metrics()["event_count"]); self.assertEqual(1, len(adapter.active_processes()))
            log_path.write_text('{"event":"process_started","pid":42}\nnot-json\n', encoding="utf-8")
            self.assertEqual(1, len(adapter.jsonl_events()))
            db.insert_event({**base, "event_id": "exit", "event_type": "process_exited", "pid": 42, "process_name": "python.exe"})
            self.assertEqual([], adapter.active_processes())


if __name__ == "__main__": unittest.main()
