from __future__ import annotations

import ast
import sys
import unittest
from pathlib import Path
from unittest.mock import patch

from backend.bootstrap import runtime


class BackgroundLifecycleTests(unittest.TestCase):
    def test_service_construction_does_not_start_the_scheduler(self) -> None:
        source = (Path(__file__).parents[1] / "backend" / "application.py").read_text(
            encoding="utf-8"
        )
        tree = ast.parse(source)
        service_class = next(
            node for node in tree.body
            if isinstance(node, ast.ClassDef) and node.name == "DashboardService"
        )
        constructor = next(
            node for node in service_class.body
            if isinstance(node, ast.FunctionDef) and node.name == "__init__"
        )
        called_methods = {
            node.func.attr for node in ast.walk(constructor)
            if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute)
        }
        self.assertNotIn("start_scheduler", called_methods)

    def test_runtime_starts_jobs_after_bind_and_stops_before_close(self) -> None:
        events: list[str] = []

        class Service:
            def start_background_jobs(self) -> None:
                events.append("start-jobs")

            def stop_background_jobs(self) -> None:
                events.append("stop-jobs")

        class Server:
            def __init__(self, address: tuple[str, int], handler: object) -> None:
                events.append("bind")

            def serve_forever(self) -> None:
                events.append("serve")
                raise KeyboardInterrupt

            def server_close(self) -> None:
                events.append("close")

        with (
            patch.object(runtime, "ThreadingHTTPServer", Server),
            patch.object(sys, "argv", ["server.py", "--port", "8797"]),
        ):
            runtime.main(object, Service())

        self.assertEqual(
            events, ["bind", "start-jobs", "serve", "stop-jobs", "close"]
        )


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