"""Unit: validate_routes_content (issue #198: _merge_single_route and
add_route removed; docker exec / cp / kill paths are covered by the
integration test)."""

import tempfile
import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch

from bot_bottle import supervise
from bot_bottle.backend.egress_apply import EgressApplyError
from bot_bottle.backend.docker.egress_apply import applicator


_ROUTES_EMPTY = "routes: []\n"
_ROUTES_ONE = 'routes:\n  - host: "api.anthropic.com"\n'


class TestValidateRoutesContent(unittest.TestCase):
    def test_accepts_minimal_route_table(self):
        applicator.validate_routes_content(_ROUTES_EMPTY)
        applicator.validate_routes_content(_ROUTES_ONE)

    def test_accepts_full_route_with_matches(self):
        applicator.validate_routes_content(
            'routes:\n'
            '  - host: "api.github.com"\n'
            '    auth_scheme: "Bearer"\n'
            '    token_env: "EGRESS_TOKEN_0"\n'
            '    matches:\n'
            '      - paths:\n'
            '          - value: "/repos/x/"\n'
        )

    def test_rejects_bad_yaml(self):
        with self.assertRaises(EgressApplyError) as cm:
            applicator.validate_routes_content("routes:\n\t- host: x\n")
        self.assertIn("not valid", str(cm.exception))

    def test_rejects_missing_routes_key(self):
        with self.assertRaises(EgressApplyError):
            applicator.validate_routes_content("other: []\n")

    def test_rejects_non_list_routes(self):
        with self.assertRaises(EgressApplyError):
            applicator.validate_routes_content('routes: "not a list"\n')

    def test_rejects_partial_auth_pair(self):
        with self.assertRaises(EgressApplyError):
            applicator.validate_routes_content(
                'routes:\n'
                '  - host: "x.example"\n'
                '    auth_scheme: "Bearer"\n'
            )

    def test_rejects_log_full(self):
        with self.assertRaises(EgressApplyError) as cm:
            applicator.validate_routes_content(
                'log: 2\n'
                'routes:\n'
                '  - host: "x.example"\n'
            )
        self.assertIn("must not change egress logging", str(cm.exception))


class TestApplyRoutesChange(unittest.TestCase):
    def setUp(self):
        self._tmp = tempfile.TemporaryDirectory(prefix="egress-apply-test.")
        original = supervise.bot_bottle_root

        def fake_root() -> Path:
            return Path(self._tmp.name) / ".bot-bottle"

        supervise.bot_bottle_root = fake_root  # type: ignore[assignment]
        self.addCleanup(lambda: setattr(supervise, "bot_bottle_root", original))
        self.addCleanup(self._tmp.cleanup)

    def test_writes_live_routes_and_signals_reload(self):
        calls: list[list[str]] = []

        def fake_run(argv: list[str], **kwargs: object) -> SimpleNamespace:
            calls.append(list(argv))
            return SimpleNamespace(returncode=0, stdout="", stderr="")

        with patch(
            "bot_bottle.backend.docker.egress_apply.subprocess.run",
            side_effect=fake_run,
        ):
            before, after = applicator.apply_routes_change(
                "dev",
                "routes:\n  - host: google.com\n",
            )

        self.assertEqual("", before)
        self.assertEqual("routes:\n  - host: google.com\n", after)
        self.assertEqual(
            "routes:\n  - host: google.com\n",
            (Path(self._tmp.name) / ".bot-bottle/state/dev/egress/routes.yaml").read_text(encoding="utf-8"),
        )
        self.assertEqual(
            ["docker", "kill", "--signal", "HUP", "bot-bottle-sidecars-dev"],
            calls[0],
        )


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