from __future__ import annotations

import pytest

from src.commune_service import CommuneService, CommuneUpstreamError
from conftest import FakeClient, FakeResponse


@pytest.mark.asyncio
async def test_search_communes_transforms_coordinates() -> None:
    payload = [
        {
            "nom": "Paris",
            "codeDepartement": "75",
            "centre": {"coordinates": [2.3522, 48.8566]},
        }
    ]
    service = CommuneService(client=FakeClient(response=FakeResponse(payload)))

    result = await service.search_communes("Paris")

    assert result == [
        {
            "nom": "Paris",
            "departement": "75",
            "latitude": 48.8566,
            "longitude": 2.3522,
            "population": None,
            "surface_km2": None,
            "departement_nom": None,
            "region_nom": None,
        }
    ]


@pytest.mark.asyncio
async def test_search_communes_empty_response() -> None:
    service = CommuneService(client=FakeClient(response=FakeResponse([])))

    result = await service.search_communes("zz")

    assert result == []


@pytest.mark.asyncio
async def test_search_communes_upstream_error() -> None:
    service = CommuneService(client=FakeClient(fail=True))

    with pytest.raises(CommuneUpstreamError):
        await service.search_communes("Paris")


@pytest.mark.asyncio
async def test_search_communes_with_accents() -> None:
    payload = [
        {
            "nom": "Saint-Étienne",
            "codeDepartement": "42",
            "centre": {"coordinates": [4.3903, 45.4397]},
        }
    ]
    service = CommuneService(client=FakeClient(response=FakeResponse(payload)))

    result = await service.search_communes("saint-étienne")

    assert result[0]["nom"] == "Saint-Étienne"
    assert result[0]["latitude"] == 45.4397


def test_generate_slug_basic() -> None:
    assert CommuneService.generate_slug("Digne-les-Bains") == "digne-les-bains"


def test_generate_slug_accents() -> None:
    assert CommuneService.generate_slug("Saint-Étienne") == "saint-etienne"


def test_generate_slug_apostrophe() -> None:
    assert CommuneService.generate_slug("L'Haÿ-les-Roses") == "lhay-les-roses"


@pytest.mark.asyncio
async def test_resolve_slug_ok() -> None:
    payload = [
        {
            "nom": "Paris",
            "codeDepartement": "75",
            "centre": {"coordinates": [2.3522, 48.8566]},
        }
    ]
    service = CommuneService(client=FakeClient(response=FakeResponse(payload)))

    result = await service.resolve_slug("paris-75")

    assert result is not None
    assert result["nom"] == "Paris"
    assert result["departement"] == "75"
    assert result["slug"] == "paris-75"
    assert result["population"] is None


@pytest.mark.asyncio
async def test_resolve_slug_not_found() -> None:
    service = CommuneService(client=FakeClient(response=FakeResponse([])))

    result = await service.resolve_slug("xyz-99")

    assert result is None


def test_generate_slug_paris() -> None:
    assert CommuneService.generate_slug("Paris") == "paris"


def test_generate_slug_aix() -> None:
    assert CommuneService.generate_slug("Aix-en-Provence") == "aix-en-provence"


def test_generate_slug_noisy() -> None:
    assert CommuneService.generate_slug("Noisy-le-Grand") == "noisy-le-grand"


def test_generate_slug_empty() -> None:
    assert CommuneService.generate_slug("") == ""


@pytest.mark.asyncio
async def test_resolve_slug_invalid_no_dept() -> None:
    service = CommuneService(client=FakeClient(response=FakeResponse([])))

    result = await service.resolve_slug("invalidslug")

    assert result is None


def test_normalize_commune_enriched() -> None:
    item = {
        "nom": "Digne-les-Bains",
        "codeDepartement": "04",
        "centre": {"coordinates": [6.24, 44.09]},
        "population": 16844,
        "surface": 11709,
        "departement": {"code": "04", "nom": "Alpes-de-Haute-Provence"},
        "region": {"code": "93", "nom": "Provence-Alpes-Cote d'Azur"},
    }

    result = CommuneService._normalize_commune(item)

    assert result["population"] == 16844
    assert result["surface_km2"] == 117.1
    assert result["departement_nom"] == "Alpes-de-Haute-Provence"
    assert result["region_nom"] == "Provence-Alpes-Cote d'Azur"


def test_normalize_commune_missing_enriched() -> None:
    item = {
        "nom": "X",
        "codeDepartement": "01",
        "centre": {"coordinates": [4.0, 45.0]},
    }

    result = CommuneService._normalize_commune(item)

    assert result["population"] is None
    assert result["surface_km2"] is None
    assert result["departement_nom"] is None
    assert result["region_nom"] is None


@pytest.mark.asyncio
async def test_resolve_slug_enriched_fields() -> None:
    payload = [
        {
            "nom": "Paris",
            "codeDepartement": "75",
            "centre": {"coordinates": [2.3522, 48.8566]},
            "population": 2102650,
            "surface": 10540,
            "departement": {"nom": "Paris"},
            "region": {"nom": "Ile-de-France"},
        }
    ]
    service = CommuneService(client=FakeClient(response=FakeResponse(payload)))

    result = await service.resolve_slug("paris-75")

    assert result is not None
    assert result["population"] == 2102650
    assert result["surface_km2"] == 105.4
    assert result["departement_nom"] == "Paris"
    assert result["region_nom"] == "Ile-de-France"
