from unittest.mock import patch

import pytest

from planemapper.provisioning import ProvisioningError
from planemapper.provisioning.portal import app


@pytest.fixture
def client():
    app.config["TESTING"] = True
    with app.test_client() as c:
        yield c


def test_index_returns_200(client) -> None:
    resp = client.get("/")
    assert resp.status_code == 200


def test_index_contains_form_fields(client) -> None:
    resp = client.get("/")
    data = resp.data.decode()
    assert 'name="location"' in data
    assert 'name="radius"' in data
    assert 'name="wifi_ssid"' in data
    assert 'name="wifi_password"' in data
    assert "Find location" in data
    assert "Set up device" in data


def test_generate_204_redirects_to_index(client) -> None:
    resp = client.get("/generate_204")
    assert resp.status_code in (301, 302)
    assert resp.headers["Location"].endswith("/")


def test_hotspot_detect_redirects_to_index(client) -> None:
    resp = client.get("/hotspot-detect.html")
    assert resp.status_code in (301, 302)


def test_ncsi_redirects_to_index(client) -> None:
    resp = client.get("/ncsi.txt")
    assert resp.status_code in (301, 302)


def test_unknown_route_redirects_to_index(client) -> None:
    resp = client.get("/some/random/path")
    assert resp.status_code in (301, 302)


def test_find_location_success(client) -> None:
    mock_resolve = patch(
        "planemapper.provisioning.portal.location.resolve", return_value=(51.5, -0.1, "London")
    )
    with mock_resolve:
        resp = client.post("/find-location", data={"location": "EGLL", "radius": "100"})
    assert resp.status_code == 200
    data = resp.data.decode()
    assert "London" in data
    assert "51.5" in data


def test_find_location_error(client) -> None:
    with patch(
        "planemapper.provisioning.portal.location.resolve",
        side_effect=ValueError("ICAO code not found — try an address instead"),
    ):
        resp = client.post("/find-location", data={"location": "ZZZZ", "radius": "100"})
    assert resp.status_code == 200
    assert "ICAO code not found" in resp.data.decode()


def test_submit_success(client) -> None:
    with (
        patch("planemapper.provisioning.portal.wifi.join_home_wifi"),
        patch("planemapper.provisioning.portal.tiles.download_and_composite"),
        patch("planemapper.provisioning.portal.airspace.download"),
        patch("planemapper.provisioning.portal.tiles.validate_cache"),
        patch("planemapper.provisioning.portal.config.write"),
        patch("planemapper.provisioning.portal.wifi.kill_wifi"),
    ):
        resp = client.post(
            "/submit",
            data={
                "confirmed_lat": "51.5",
                "confirmed_lon": "-0.1",
                "confirmed_name": "London",
                "radius": "100",
                "wifi_ssid": "HomeNet",
                "wifi_password": "secret",
            },
        )
    assert resp.status_code == 200
    assert b"Setup complete" in resp.data


def test_submit_validation_failure(client) -> None:
    with (
        patch("planemapper.provisioning.portal.wifi.join_home_wifi"),
        patch("planemapper.provisioning.portal.tiles.download_and_composite"),
        patch("planemapper.provisioning.portal.airspace.download"),
        patch(
            "planemapper.provisioning.portal.tiles.validate_cache",
            side_effect=ProvisioningError("bad png"),
        ),
        patch("planemapper.provisioning.portal.config.write"),
        patch("planemapper.provisioning.portal.wifi.kill_wifi"),
    ):
        resp = client.post(
            "/submit",
            data={
                "confirmed_lat": "51.5",
                "confirmed_lon": "-0.1",
                "confirmed_name": "London",
                "radius": "100",
                "wifi_ssid": "HomeNet",
                "wifi_password": "secret",
            },
        )
    assert resp.status_code == 200
    assert b"Try again" in resp.data
