"""
Tests for the sections `google_maps_url` field (retained as optional section
metadata) and the "Section markers" QR code, which now resolves to the
cemetery-wide configured SECTION_MARKERS_MAPS_URL rather than a per-section link.

Covers:
  - CreateSectionRequest / UpdateSectionRequest schema validation
  - Persisting/returning google_maps_url via the sections CRUD endpoints
  - QRCodeService.generate_one for qr_type="section" using the configured URL
"""
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
import pytest_asyncio
from httpx import AsyncClient
from pydantic import ValidationError as PydanticValidationError

BASE = "/api/v1/sections"


@pytest_asyncio.fixture
async def tenant_headers(auth_headers, test_account):
    """auth_headers plus X-Tenant-ID — the qr-codes endpoints resolve tenant
    context via TenantMiddleware/require_tenant, which (unlike the sections
    endpoints, which read current_user.tenant_id) needs an explicit tenant
    header in tests since there's no real subdomain host to resolve from."""
    return {**auth_headers, "X-Tenant-ID": str(test_account.id)}


# ---------------------------------------------------------------------------
# 1. Schema validation (synchronous — no DB needed)
# ---------------------------------------------------------------------------

class TestGoogleMapsUrlSchema:
    def test_create_accepts_https_url(self):
        from src.apps.sections.schemas.requests import CreateSectionRequest
        req = CreateSectionRequest(
            code="A", name="Garden of Peace",
            google_maps_url="https://maps.app.goo.gl/abc123",
        )
        assert req.google_maps_url == "https://maps.app.goo.gl/abc123"

    def test_create_rejects_non_https_scheme(self):
        from src.apps.sections.schemas.requests import CreateSectionRequest
        with pytest.raises(PydanticValidationError):
            CreateSectionRequest(
                code="A", name="Garden of Peace",
                google_maps_url="javascript:alert(1)",
            )

    def test_create_omitted_defaults_to_none(self):
        from src.apps.sections.schemas.requests import CreateSectionRequest
        req = CreateSectionRequest(code="A", name="Garden of Peace")
        assert req.google_maps_url is None

    def test_update_accepts_https_url(self):
        from src.apps.sections.schemas.requests import UpdateSectionRequest
        req = UpdateSectionRequest(google_maps_url="https://goo.gl/maps/xyz")
        assert req.google_maps_url == "https://goo.gl/maps/xyz"

    def test_update_rejects_http_scheme(self):
        from src.apps.sections.schemas.requests import UpdateSectionRequest
        with pytest.raises(PydanticValidationError):
            UpdateSectionRequest(google_maps_url="http://insecure.example.com")


# ---------------------------------------------------------------------------
# 2. CRUD round-trip via the existing sections endpoints
# ---------------------------------------------------------------------------

@pytest.mark.asyncio
async def test_create_section_persists_google_maps_url(
    client: AsyncClient, auth_headers, test_account
):
    resp = await client.post(
        BASE,
        json={
            "code": "GM",
            "name": "Google Maps Section",
            "google_maps_url": "https://maps.app.goo.gl/testlink",
        },
        headers=auth_headers,
    )
    assert resp.status_code == 201, resp.text
    data = resp.json()["data"]
    assert data["google_maps_url"] == "https://maps.app.goo.gl/testlink"


@pytest.mark.asyncio
async def test_update_section_sets_google_maps_url(
    client: AsyncClient, auth_headers, test_account
):
    created = (
        await client.post(
            BASE, json={"code": "UP", "name": "Update Section"}, headers=auth_headers
        )
    ).json()["data"]
    assert created["google_maps_url"] is None

    resp = await client.patch(
        f"{BASE}/{created['id']}",
        json={"google_maps_url": "https://maps.app.goo.gl/updated"},
        headers=auth_headers,
    )
    assert resp.status_code == 200
    assert resp.json()["data"]["google_maps_url"] == "https://maps.app.goo.gl/updated"


@pytest.mark.asyncio
async def test_get_section_returns_google_maps_url(
    client: AsyncClient, auth_headers, test_account
):
    created = (
        await client.post(
            BASE,
            json={
                "code": "GET",
                "name": "Get Section",
                "google_maps_url": "https://maps.app.goo.gl/getlink",
            },
            headers=auth_headers,
        )
    ).json()["data"]

    resp = await client.get(f"{BASE}/{created['id']}", headers=auth_headers)
    assert resp.status_code == 200
    assert resp.json()["data"]["google_maps_url"] == "https://maps.app.goo.gl/getlink"


# ---------------------------------------------------------------------------
# 3. QRCodeService.generate_one for qr_type="section"
# ---------------------------------------------------------------------------

@pytest.mark.asyncio
async def test_generate_section_qr_uses_configured_maps_url(
    client: AsyncClient, tenant_headers, test_account
):
    """A single "Section markers" QR resolves to the cemetery-wide configured
    SECTION_MARKERS_MAPS_URL — no per-section lookup, so it succeeds without
    any Section row existing for the reference_id."""
    from src.core.config import settings

    with patch("arq.create_pool", new_callable=AsyncMock) as mock_pool:
        mock_arq = AsyncMock()
        mock_arq.enqueue_job = AsyncMock(return_value=MagicMock(job_id="job-1"))
        mock_arq.aclose = AsyncMock()
        mock_pool.return_value = mock_arq

        resp = await client.post(
            "/api/v1/settings/qr-codes/generate",
            json={"qr_type": "section", "reference_id": "main"},
            headers=tenant_headers,
        )

    assert resp.status_code == 202, resp.text

    list_resp = await client.get(
        "/api/v1/settings/qr-codes",
        params={"qr_type": "section"},
        headers=tenant_headers,
    )
    assert list_resp.status_code == 200
    items = list_resp.json()["data"]
    matching = [i for i in items if i["reference_id"] == "main"]
    assert len(matching) == 1
    assert matching[0]["content_url"] == settings.SECTION_MARKERS_MAPS_URL


@pytest.mark.asyncio
async def test_generate_section_qr_uses_configured_cemetery_coordinates(
    client: AsyncClient, tenant_headers, test_account, db_session
):
    """When the cemetery has configured coordinates (the same location
    "Locate cemetery" centres on), the Section markers QR resolves to a Google
    Maps deep-link for those coordinates rather than the static fallback."""
    from decimal import Decimal

    test_account.map_search_lat = Decimal("45.4215000")
    test_account.map_search_lng = Decimal("-75.6972000")
    db_session.add(test_account)
    await db_session.flush()

    with patch("arq.create_pool", new_callable=AsyncMock) as mock_pool:
        mock_arq = AsyncMock()
        mock_arq.enqueue_job = AsyncMock(return_value=MagicMock(job_id="job-2"))
        mock_arq.aclose = AsyncMock()
        mock_pool.return_value = mock_arq

        resp = await client.post(
            "/api/v1/settings/qr-codes/generate",
            json={"qr_type": "section", "reference_id": "main"},
            headers=tenant_headers,
        )

    assert resp.status_code == 202, resp.text

    list_resp = await client.get(
        "/api/v1/settings/qr-codes",
        params={"qr_type": "section"},
        headers=tenant_headers,
    )
    assert list_resp.status_code == 200
    matching = [
        i for i in list_resp.json()["data"] if i["reference_id"] == "main"
    ]
    assert len(matching) == 1
    assert matching[0]["content_url"] == (
        "https://www.google.com/maps/search/?api=1&query=45.4215%2C-75.6972"
    )


@pytest.mark.asyncio
async def test_resolve_cemetery_coords_prefers_search_when_no_boundary(
    test_account, db_session
):
    """resolve_cemetery_coords falls back to the cached geocoded coordinates
    when no boundary polygon is drawn, and returns None when neither exists."""
    from decimal import Decimal
    from src.apps.settings.services.qr_code_service import QRCodeService

    assert await QRCodeService.resolve_cemetery_coords(
        db_session, str(test_account.id)
    ) is None

    test_account.map_search_lat = Decimal("12.3456789")
    test_account.map_search_lng = Decimal("-98.7654321")
    db_session.add(test_account)
    await db_session.flush()

    coords = await QRCodeService.resolve_cemetery_coords(
        db_session, str(test_account.id)
    )
    assert coords == (12.3456789, -98.7654321)
