"""Unit tests for server_client.py -- runnable on any platform since the
HTTP layer is injected (no real network, no Windows registry required).
Run with:
    python3 -m unittest discover -s togen/display_agent_win/tests
"""
import os
import sys
import unittest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import requests  # noqa: E402

import server_client  # noqa: E402


class _FakeResponse:
    def __init__(self, status_code=200, json_data=None, text=""):
        self.status_code = status_code
        self._json = json_data if json_data is not None else {}
        self.text = text
        self.ok = 200 <= status_code < 300

    def json(self):
        return self._json

    def raise_for_status(self):
        if not self.ok:
            err = requests.exceptions.HTTPError(f"HTTP {self.status_code}")
            err.response = self
            raise err


class _FakeSession:
    def __init__(self, responses):
        # responses: list of _FakeResponse popped in call order.
        self._responses = list(responses)
        self.calls = []

    def post(self, url, json=None, headers=None, timeout=None):
        self.calls.append(("POST", url, json, headers))
        return self._responses.pop(0)

    def get(self, url, headers=None, timeout=None):
        self.calls.append(("GET", url, None, headers))
        return self._responses.pop(0)


class RegisterTests(unittest.TestCase):
    def test_register_success_returns_agent_token(self):
        session = _FakeSession([_FakeResponse(200, {"agent_token": "tok123", "agent_id": "disp_1", "status": "active"})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        data = client.register("enroll-tok", "MY-PC")
        self.assertEqual(data["agent_token"], "tok123")
        method, url, payload, headers = session.calls[0]
        self.assertEqual(url, "https://togen.example.com/signage/agents/register")
        self.assertEqual(payload["enrollment_token"], "enroll-tok")
        self.assertEqual(payload["hostname"], "MY-PC")
        self.assertEqual(payload["platform"], "windows")

    def test_register_missing_token_raises(self):
        session = _FakeSession([_FakeResponse(200, {"status": "active"})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        with self.assertRaises(ValueError):
            client.register("enroll-tok", "MY-PC")

    def test_register_http_error_propagates(self):
        session = _FakeSession([_FakeResponse(401, {"error": "Invalid enrollment_token."})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        with self.assertRaises(requests.exceptions.HTTPError) as ctx:
            client.register("bad-tok", "MY-PC")
        self.assertEqual(ctx.exception.response.status_code, 401)

    def test_base_url_trailing_slash_stripped(self):
        session = _FakeSession([_FakeResponse(200, {"agent_token": "t"})])
        client = server_client.DisplayAgentClient("https://togen.example.com/", session=session)
        client.register("tok", "host")
        self.assertEqual(session.calls[0][1], "https://togen.example.com/signage/agents/register")


class CheckinTests(unittest.TestCase):
    def test_checkin_success(self):
        session = _FakeSession([_FakeResponse(200, {"ok": True, "poll_seconds": 15})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        data = client.checkin("agent-tok")
        self.assertTrue(data["ok"])
        method, url, payload, headers = session.calls[0]
        self.assertEqual(headers["Authorization"], "Bearer agent-tok")
        self.assertNotIn("window_layer_effective", payload)

    def test_checkin_includes_effective_layer_when_given(self):
        session = _FakeSession([_FakeResponse(200, {"ok": True})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        client.checkin("agent-tok", effective_layer="bottom")
        payload = session.calls[0][2]
        self.assertEqual(payload["window_layer_effective"], "bottom")

    def test_checkin_401_raises_http_error(self):
        session = _FakeSession([_FakeResponse(401, {"error": "Invalid or revoked agent_token."})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        with self.assertRaises(requests.exceptions.HTTPError) as ctx:
            client.checkin("dead-tok")
        self.assertEqual(ctx.exception.response.status_code, 401)


class DisplayConfigTests(unittest.TestCase):
    def test_get_display_config_success(self):
        session = _FakeSession([_FakeResponse(200, {"assigned": True, "window": {"layer": "bottom"}})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        cfg = client.get_display_config("agent-tok")
        self.assertEqual(cfg["window"]["layer"], "bottom")
        method, url, payload, headers = session.calls[0]
        self.assertEqual(method, "GET")
        self.assertEqual(headers["Authorization"], "Bearer agent-tok")

    def test_get_display_config_401(self):
        session = _FakeSession([_FakeResponse(401, {"error": "Invalid or revoked display token."})])
        client = server_client.DisplayAgentClient("https://togen.example.com", session=session)
        with self.assertRaises(requests.exceptions.HTTPError):
            client.get_display_config("dead-tok")

    def test_display_url(self):
        client = server_client.DisplayAgentClient("https://togen.example.com")
        self.assertEqual(client.display_url("tok"), "https://togen.example.com/display?token=tok")


class SanitizeWindowConfigTests(unittest.TestCase):
    def test_defaults_when_missing(self):
        cfg = server_client.sanitize_window_config(None)
        self.assertEqual(cfg, {"layer": "top", "monitor": "primary", "windowed": {}})

    def test_passes_through_valid_values(self):
        cfg = server_client.sanitize_window_config({
            "layer": "wallpaper", "monitor": 2,
            "windowed": {"x": 1, "y": 2, "width": 3, "height": 4},
        })
        self.assertEqual(cfg["layer"], "wallpaper")
        self.assertEqual(cfg["monitor"], 2)
        self.assertEqual(cfg["windowed"]["width"], 3)

    def test_non_dict_windowed_becomes_empty(self):
        cfg = server_client.sanitize_window_config({"layer": "top", "windowed": "nope"})
        self.assertEqual(cfg["windowed"], {})


class MachineIdAndTokenStorageTests(unittest.TestCase):
    def test_get_machine_id_off_windows_returns_uuid(self):
        if server_client.IS_WINDOWS:
            self.skipTest("Windows-only path exercised elsewhere")
        mid = server_client.get_machine_id()
        self.assertEqual(len(mid), 36)  # uuid4 string form

    def test_load_agent_token_off_windows_without_keyring_is_none(self):
        if server_client.IS_WINDOWS:
            self.skipTest("Windows-only path exercised elsewhere")
        if server_client._HAS_KEYRING:
            self.skipTest("keyring present in this environment")
        self.assertIsNone(server_client.load_agent_token())


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