from __future__ import annotations

import logging
import pathlib
from unittest.mock import MagicMock, patch

import pytest
from PIL import Image

from planemapper.display import NullDisplay
from planemapper.fetcher import FileFixtureFetcher
from planemapper.main import _run_one_cycle
from planemapper.renderer.projection import MapBounds
from planemapper.renderer.renderer import Renderer

FIXTURE_DIR = pathlib.Path(__file__).parent / "fixtures"


@pytest.fixture
def renderer(monkeypatch: pytest.MonkeyPatch) -> Renderer:
    monkeypatch.setattr(
        "planemapper.renderer.airspace.AIRSPACE_PATH",
        FIXTURE_DIR / "airspace_sample.geojson",
    )
    base_map = Image.new("RGB", (800, 480), color=(255, 255, 255))
    bounds = MapBounds(home_lat=53.0, home_lon=-6.0, radius_nm=100.0)
    return Renderer(base_map, bounds)


def test_run_one_cycle_calls_display_show(renderer: Renderer) -> None:
    fetcher = FileFixtureFetcher(FIXTURE_DIR / "aircraft_sample.json")
    display = NullDisplay()
    display_mock = MagicMock(wraps=display)
    _run_one_cycle(renderer, fetcher, display_mock, [])
    display_mock.show.assert_called_once()


def test_run_one_cycle_logs_warning_when_slow(
    renderer: Renderer, caplog: pytest.LogCaptureFixture
) -> None:
    fetcher = FileFixtureFetcher(FIXTURE_DIR / "aircraft_sample.json")
    display = NullDisplay()
    # Simulate 43s total: t0=0, t1=1, t2=2, t3=43
    with patch("planemapper.main.time.monotonic", side_effect=[0.0, 1.0, 2.0, 43.0]):
        with caplog.at_level(logging.WARNING, logger="planemapper.main"):
            _run_one_cycle(renderer, fetcher, display, [])
    assert any("render slow" in r.message for r in caplog.records)


def test_provision_main_exits_if_already_provisioned() -> None:
    with patch("planemapper.provisioning.config.read", return_value={"provisioned": True}):
        with patch("planemapper.provisioning.wifi.start_ap") as mock_ap:
            from planemapper.provision import main as provision_main

            provision_main()
            mock_ap.assert_not_called()
