"""FastMCP integration tests — tool calls against the real server, HTTP mocked."""

import json
from io import BytesIO

import httpx
import respx
from fastmcp import Client
from PIL import Image as PILImage

import mcgibs.server as server_module
from mcgibs.client import GIBSClient
from mcgibs.server import mcp


async def _init_mock_client(capabilities_xml: str) -> GIBSClient:
    """Create and initialize a GIBSClient with mocked capabilities."""
    client = GIBSClient()
    await client.initialize()
    return client


@respx.mock
async def test_search_tool(capabilities_xml):
    """search_gibs_layers finds the sea ice layer by keyword."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool("search_gibs_layers", {"query": "sea ice"})
            text = result.content[0].text
            assert "AMSR2" in text
            assert "Sea Ice" in text
            # Should not match unrelated layers
            assert "Surface Air Temperature" not in text
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_get_layer_info_tool(capabilities_xml, layer_metadata_json):
    """get_layer_info returns enriched JSON for the true color layer."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    layer_id = "MODIS_Terra_CorrectedReflectance_TrueColor"
    respx.get(url__regex=rf".*layer-metadata.*/{layer_id}\.json").mock(
        return_value=httpx.Response(200, text=layer_metadata_json)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool("get_layer_info", {"layer_id": layer_id})
            text = result.content[0].text
            info = json.loads(text)

            assert info["identifier"] == layer_id
            assert info["instrument"] == "MODIS"
            assert info["platform"] == "Terra"
            assert info["ongoing"] is True
            assert "time" in info
            assert info["time"]["start"] == "2000-02-24"
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_resolve_place_tool(capabilities_xml):
    """resolve_place geocodes a place name via mocked Nominatim."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    nominatim_response = [
        {
            "display_name": "Tokyo, Japan",
            "lat": "35.6762",
            "lon": "139.6503",
            "boundingbox": ["35.5190", "35.8178", "138.9428", "139.9200"],
            "osm_type": "relation",
            "importance": 0.82,
        }
    ]
    respx.get(url__regex=r".*nominatim.*search.*").mock(
        return_value=httpx.Response(200, json=nominatim_response)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool("resolve_place", {"place": "Tokyo"})
            text = result.content[0].text
            data = json.loads(text)

            assert data["display_name"] == "Tokyo, Japan"
            assert abs(data["lat"] - 35.6762) < 0.01
            assert abs(data["lon"] - 139.6503) < 0.01
            assert "bbox" in data
            assert data["bbox"]["west"] < data["bbox"]["east"]
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_build_tile_url_tool(capabilities_xml):
    """build_tile_url returns a properly formatted WMTS tile URL."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "build_tile_url",
                {
                    "layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor",
                    "date": "2025-06-01",
                    "zoom": 3,
                    "row": 2,
                    "col": 4,
                },
            )
            url = result.content[0].text

            assert "MODIS_Terra_CorrectedReflectance_TrueColor" in url
            assert "2025-06-01" in url
            assert "epsg4326" in url
            # True color layer uses JPEG and 250m matrix set
            assert url.endswith(".jpg")
            assert "/250m/" in url
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_list_tools(capabilities_xml):
    """All expected tools are registered on the MCP server."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            tools = await client.list_tools()
            tool_names = {t.name for t in tools}

            expected = {
                "search_gibs_layers",
                "get_layer_info",
                "list_measurements",
                "check_layer_dates",
                "get_imagery",
                "compare_dates",
                "get_imagery_composite",
                "explain_layer_colormap",
                "get_legend",
                "resolve_place",
                "build_tile_url",
                "query_point",
                "get_time_series",
            }

            for name in expected:
                assert name in tool_names, f"Missing tool: {name}"
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# Image() return type tests
# ---------------------------------------------------------------------------


def _make_fake_jpeg() -> bytes:
    """Create a tiny valid JPEG for mocking WMS responses."""
    buf = BytesIO()
    PILImage.new("RGB", (10, 10), "blue").save(buf, format="JPEG")
    return buf.getvalue()


@respx.mock
async def test_get_imagery_returns_image_content(capabilities_xml):
    """get_imagery returns TextContent + ImageContent (not raw dicts)."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    respx.get(url__regex=r".*wms\.cgi.*").mock(
        return_value=httpx.Response(
            200, content=_make_fake_jpeg(), headers={"content-type": "image/jpeg"}
        )
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "get_imagery",
                {
                    "layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor",
                    "date": "2025-06-01",
                    "bbox": [-120.0, 30.0, -110.0, 40.0],
                },
            )
            assert len(result.content) == 2
            assert result.content[0].type == "text"
            assert "Corrected Reflectance" in result.content[0].text
            assert result.content[1].type == "image"
            assert result.content[1].mimeType == "image/jpeg"
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_get_legend_returns_image_content(capabilities_xml):
    """get_legend returns TextContent + ImageContent for layers with legends."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    fake_png = BytesIO()
    PILImage.new("RGB", (200, 20), "white").save(fake_png, format="PNG")
    respx.get(url__regex=r".*legends/.*\.png").mock(
        return_value=httpx.Response(
            200, content=fake_png.getvalue(), headers={"content-type": "image/png"}
        )
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "get_legend",
                {"layer_id": "AMSR2_Sea_Ice_Concentration_12km_Monthly"},
            )
            assert len(result.content) == 2
            assert result.content[0].type == "text"
            assert result.content[1].type == "image"
            assert result.content[1].mimeType == "image/png"
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# Dynamic resource tests
# ---------------------------------------------------------------------------


@respx.mock
async def test_list_resources(capabilities_xml):
    """Server exposes all expected resources including dynamic templates."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            templates = await client.list_resource_templates()
            template_uris = {t.uriTemplate for t in templates}

            assert "gibs://layer/{layer_id}" in template_uris
            assert "gibs://colormap/{layer_id}" in template_uris
            assert "gibs://dates/{layer_id}" in template_uris
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# Prompt tests
# ---------------------------------------------------------------------------


@respx.mock
async def test_list_prompts(capabilities_xml):
    """All expected prompts are registered on the MCP server."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            prompts = await client.list_prompts()
            prompt_names = {p.name for p in prompts}

            expected = {
                "investigate_event",
                "earth_overview",
                "satellite_snapshot",
                "climate_monitor",
                "layer_deep_dive",
                "multi_layer_story",
                "polar_watch",
                "quantitative_snapshot",
                "seasonal_timelapse",
            }

            for name in expected:
                assert name in prompt_names, f"Missing prompt: {name}"
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_satellite_snapshot_prompt(capabilities_xml):
    """satellite_snapshot prompt includes the place name and expected tool references."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.get_prompt(
                "satellite_snapshot", {"place": "Tokyo", "date": "2025-06-01"}
            )
            text = result.messages[0].content.text

            assert "Tokyo" in text
            assert "resolve_place" in text
            assert "get_imagery" in text or "get_imagery_composite" in text
            assert "MODIS_Terra_CorrectedReflectance_TrueColor" in text
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_colormap_resource(capabilities_xml, colormap_xml):
    """gibs://colormap/{layer_id} returns colormap explanation text."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    respx.get(url__regex=r".*colormaps/v1\.3/.*\.xml").mock(
        return_value=httpx.Response(200, text=colormap_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.read_resource(
                "gibs://colormap/AIRS_L3_Surface_Air_Temperature_Daily_Day"
            )
            text = result[0].text
            assert "Surface Air Temperature" in text
            assert "K" in text
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# query_point tests
# ---------------------------------------------------------------------------


def _make_fake_png(rgb: tuple[int, int, int], size: int = 3) -> bytes:
    """Create a tiny PNG with uniform color for mocking point queries."""
    buf = BytesIO()
    PILImage.new("RGBA", (size, size), (*rgb, 255)).save(buf, format="PNG")
    return buf.getvalue()


@respx.mock
async def test_query_point(capabilities_xml, colormap_xml):
    """query_point reverse-maps pixel RGB through colormap to data value."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    # Return a 3x3 PNG with rgb (255,100,50) → maps to [290,300) K
    respx.get(url__regex=r".*wms\.cgi.*").mock(
        return_value=httpx.Response(
            200,
            content=_make_fake_png((255, 100, 50)),
            headers={"content-type": "image/png"},
        )
    )
    respx.get(url__regex=r".*colormaps/v1\.3/.*\.xml").mock(
        return_value=httpx.Response(200, text=colormap_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "query_point",
                {
                    "layer_id": "AIRS_L3_Surface_Air_Temperature_Daily_Day",
                    "date": "2025-06-01",
                    "lat": 35.67,
                    "lon": 139.65,
                },
            )
            data = json.loads(result.content[0].text)

            assert data["lat"] == 35.67
            assert data["lon"] == 139.65
            assert data["quality"] == "exact"  # exact RGB match
            assert "value" in data
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_query_point_no_colormap(capabilities_xml):
    """query_point returns error for layers without colormaps."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "query_point",
                {
                    "layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor",
                    "date": "2025-06-01",
                    "lat": 35.67,
                    "lon": 139.65,
                },
            )
            text = result.content[0].text
            assert "no colormap" in text
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# get_time_series tests
# ---------------------------------------------------------------------------


@respx.mock
async def test_get_time_series(capabilities_xml):
    """get_time_series returns multiple dated images."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    respx.get(url__regex=r".*wms\.cgi.*").mock(
        return_value=httpx.Response(
            200,
            content=_make_fake_jpeg(),
            headers={"content-type": "image/jpeg"},
        )
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "get_time_series",
                {
                    "layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor",
                    "start_date": "2025-01-01",
                    "end_date": "2025-06-01",
                    "bbox": [-120.0, 30.0, -110.0, 40.0],
                    "steps": 3,
                },
            )
            # 3 steps → 3 text labels + 3 images = 6 content items
            texts = [c for c in result.content if c.type == "text"]
            images = [c for c in result.content if c.type == "image"]

            assert len(texts) == 3
            assert len(images) == 3
            assert "2025-01-01" in texts[0].text
            assert "2025-06-01" in texts[-1].text
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# New prompt tests
# ---------------------------------------------------------------------------


@respx.mock
async def test_quantitative_snapshot_prompt(capabilities_xml):
    """quantitative_snapshot prompt includes locations and tool references."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.get_prompt(
                "quantitative_snapshot",
                {
                    "layer_id": "AIRS_L3_Surface_Air_Temperature_Daily_Day",
                    "locations": "Tokyo, Sydney",
                    "date": "2025-06-01",
                },
            )
            text = result.messages[0].content.text

            assert "Tokyo" in text
            assert "Sydney" in text
            assert "query_point" in text
            assert "explain_layer_colormap" in text
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_seasonal_timelapse_prompt(capabilities_xml):
    """seasonal_timelapse prompt includes dates and get_time_series reference."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.get_prompt(
                "seasonal_timelapse",
                {
                    "layer_id": "MODIS_Terra_CorrectedReflectance_TrueColor",
                    "location": "Amazon Rainforest",
                    "start_date": "2025-01-01",
                    "end_date": "2025-12-01",
                },
            )
            text = result.messages[0].content.text

            assert "Amazon Rainforest" in text
            assert "get_time_series" in text
            assert "2025-01-01" in text
            assert "2025-12-01" in text
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# Taxonomy: concept_ids and orbit_direction enrichment
# ---------------------------------------------------------------------------


@respx.mock
async def test_get_layer_info_includes_concept_ids(capabilities_xml, layer_metadata_json):
    """get_layer_info output includes CMR URLs from conceptIds."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    layer_id = "MODIS_Terra_CorrectedReflectance_TrueColor"
    respx.get(url__regex=rf".*layer-metadata.*/{layer_id}\.json").mock(
        return_value=httpx.Response(200, text=layer_metadata_json)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool("get_layer_info", {"layer_id": layer_id})
            text = result.content[0].text
            info = json.loads(text)

            assert "concept_ids" in info
            assert len(info["concept_ids"]) >= 1
            assert "cmr_url" in info["concept_ids"][0]
            assert "cmr.earthdata.nasa.gov" in info["concept_ids"][0]["cmr_url"]
            assert info["concept_ids"][0]["value"] == "C1219032686-LANCEMODIS"
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_get_layer_info_includes_orbit_direction(capabilities_xml, layer_metadata_json):
    """get_layer_info output includes orbit_direction from metadata."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )
    layer_id = "MODIS_Terra_CorrectedReflectance_TrueColor"
    respx.get(url__regex=rf".*layer-metadata.*/{layer_id}\.json").mock(
        return_value=httpx.Response(200, text=layer_metadata_json)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool("get_layer_info", {"layer_id": layer_id})
            text = result.content[0].text
            info = json.loads(text)

            assert "orbit_direction" in info
            assert "descending" in info["orbit_direction"]
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# Taxonomy: new resources
# ---------------------------------------------------------------------------


@respx.mock
async def test_disciplines_resource(capabilities_xml):
    """gibs://disciplines returns JSON with discipline names and layer counts."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.read_resource("gibs://disciplines")
            data = json.loads(result[0].text)

            # Should have disciplines from taxonomy
            if "error" not in data:
                assert isinstance(data, dict)
                assert len(data) > 0
                # Each discipline has measurements and layer_count
                for _name, info in data.items():
                    assert "measurements" in info
                    assert "layer_count" in info
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_hazards_resource(capabilities_xml):
    """gibs://hazards returns JSON with hazard categories."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.read_resource("gibs://hazards")
            data = json.loads(result[0].text)

            if "error" not in data:
                assert isinstance(data, dict)
                for _name, info in data.items():
                    assert "measurements" in info
                    assert "layer_count" in info
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_measurement_resource(capabilities_xml):
    """gibs://measurement/{name} returns sources for a specific measurement."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        taxonomy = server_module._client.taxonomy
        if taxonomy and taxonomy.measurements:
            meas_name = next(iter(taxonomy.measurements))
            async with Client(mcp) as client:
                result = await client.read_resource(f"gibs://measurement/{meas_name}")
                data = json.loads(result[0].text)

                assert "sources" in data
                assert "id" in data
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_search_includes_layergroup(capabilities_xml):
    """search output shows [layergroup] when taxonomy is loaded."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        # Manually set layergroup for test
        layer = server_module._client.get_layer("AMSR2_Sea_Ice_Concentration_12km_Monthly")
        if layer:
            layer.layergroup = "Sea Ice"

        async with Client(mcp) as client:
            result = await client.call_tool("search_gibs_layers", {"query": "sea ice"})
            text = result.content[0].text
            assert "[Sea Ice]" in text
    finally:
        await server_module._client.close()
        server_module._client = None


@respx.mock
async def test_list_resources_includes_taxonomy(capabilities_xml):
    """Server exposes taxonomy resource templates."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            templates = await client.list_resource_templates()
            template_uris = {t.uriTemplate for t in templates}

            assert "gibs://measurement/{name}" in template_uris

            resources = await client.list_resources()
            resource_uris = {str(r.uri) for r in resources}

            assert "gibs://disciplines" in resource_uris
            assert "gibs://hazards" in resource_uris
    finally:
        await server_module._client.close()
        server_module._client = None


# ---------------------------------------------------------------------------
# Sub-daily date generation tests
# ---------------------------------------------------------------------------


def test_generate_dates_daily():
    """Date-only generation should produce YYYY-MM-DD strings."""
    from mcgibs.server import _generate_dates

    dates = _generate_dates("2025-01-01", "2025-01-05", 3)
    assert len(dates) == 3
    assert dates[0] == "2025-01-01"
    assert dates[-1] == "2025-01-05"
    # All should be date-only (no T)
    assert all("T" not in d for d in dates)


def test_generate_dates_subdaily():
    """Datetime generation should produce YYYY-MM-DDTHH:MM:SSZ strings."""
    from mcgibs.server import _generate_dates

    dates = _generate_dates(
        "2024-01-01T00:00:00Z",
        "2024-01-01T02:00:00Z",
        3,
    )
    assert len(dates) == 3
    assert dates[0] == "2024-01-01T00:00:00Z"
    assert dates[1] == "2024-01-01T01:00:00Z"
    assert dates[2] == "2024-01-01T02:00:00Z"


def test_generate_dates_single_step():
    """Single step should return just the start."""
    from mcgibs.server import _generate_dates

    dates = _generate_dates("2025-01-01", "2025-06-01", 1)
    assert dates == ["2025-01-01"]

    dates_dt = _generate_dates("2024-01-01T00:00:00Z", "2024-01-01T12:00:00Z", 1)
    assert dates_dt == ["2024-01-01T00:00:00Z"]


def test_parse_timestamp_z_suffix():
    """_parse_timestamp should handle Z suffix."""
    from mcgibs.server import _parse_timestamp

    dt = _parse_timestamp("2024-06-15T12:30:00Z")
    assert dt.year == 2024
    assert dt.month == 6
    assert dt.hour == 12
    assert dt.minute == 30


def test_parse_timestamp_offset():
    """_parse_timestamp should handle +00:00 offset."""
    from mcgibs.server import _parse_timestamp

    dt = _parse_timestamp("2024-06-15T12:30:00+00:00")
    assert dt.year == 2024
    assert dt.hour == 12


def test_format_timestamp():
    """_format_timestamp should produce YYYY-MM-DDTHH:MM:SSZ."""
    from datetime import UTC, datetime

    from mcgibs.server import _format_timestamp

    dt = datetime(2024, 3, 15, 8, 30, 0, tzinfo=UTC)
    assert _format_timestamp(dt) == "2024-03-15T08:30:00Z"


# ---------------------------------------------------------------------------
# Search sub-daily hint test
# ---------------------------------------------------------------------------


@respx.mock
async def test_search_shows_subdaily_hint(capabilities_xml):
    """Search output shows [sub-daily: PT10M] for GOES layers."""
    respx.get(url__regex=r".*WMTSCapabilities\.xml").mock(
        return_value=httpx.Response(200, text=capabilities_xml)
    )

    server_module._client = await _init_mock_client(capabilities_xml)
    try:
        async with Client(mcp) as client:
            result = await client.call_tool(
                "search_gibs_layers", {"query": "GOES"}
            )
            text = result.content[0].text
            assert "[sub-daily: PT10M]" in text
            assert "GOES-West" in text
    finally:
        await server_module._client.close()
        server_module._client = None
