"""Offline adapter for frozen route-local OpenStreetMap fixture JSON."""

from __future__ import annotations

import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Mapping

from mountain_twin.trail_character.contracts import GeoCoordinate, MappedFeature, MappedSource

FIXTURE_SCHEMA_VERSION = "osm_route_local_fixture_v0_1"


@dataclass(frozen=True)
class FrozenOsmFixture:
    fixture_id: str
    source: MappedSource
    manifest: Mapping[str, Any]
    features: tuple[MappedFeature, ...]


def load_frozen_osm_fixture(path: Path) -> FrozenOsmFixture:
    """Load only frozen local JSON; no PBF, network, or tag normalisation occurs."""
    document = json.loads(path.read_text(encoding="utf-8"))
    if document.get("fixture_schema_version") != FIXTURE_SCHEMA_VERSION:
        raise ValueError("unsupported frozen OSM fixture schema")
    manifest = document.get("manifest")
    if not isinstance(manifest, dict):
        raise ValueError("frozen OSM fixture manifest is required")
    source_document = manifest.get("source")
    if not isinstance(source_document, dict):
        raise ValueError("frozen OSM fixture source metadata is required")
    source = MappedSource(
        source_id=_required(source_document, "source_id"),
        provider=_required(source_document, "provider"),
        dataset_snapshot_reference=source_document.get("dataset_snapshot_reference"),
        retrieved_at=source_document.get("retrieved_at"),
        attribution=source_document.get("attribution"),
        license=source_document.get("license"),
    )
    features = tuple(
        sorted(
            (_feature(source, item) for item in document.get("features", ())),
            key=lambda item: item.feature_id,
        )
    )
    if not features:
        raise ValueError("frozen OSM fixture has no selected candidate features")
    return FrozenOsmFixture(_required(manifest, "fixture_id"), source, manifest, features)


def _feature(source: MappedSource, value: Any) -> MappedFeature:
    if not isinstance(value, dict) or value.get("element_type") != "way":
        raise ValueError("frozen OSM fixture supports source way features only")
    tags = value.get("raw_tags")
    geometry = value.get("geometry")
    if not isinstance(tags, dict) or not isinstance(geometry, list):
        raise ValueError("frozen OSM feature tags and geometry are required")
    return MappedFeature(
        source=source,
        feature_id=_required(value, "element_id"),
        geometry=tuple(
            GeoCoordinate(float(point["latitude"]), float(point["longitude"])) for point in geometry
        ),
        raw_properties=dict(tags),
        source_element_version=value.get("element_version"),
        source_updated_at=value.get("element_timestamp"),
    )


def _required(value: Mapping[str, Any], key: str) -> str:
    item = value.get(key)
    if not isinstance(item, str) or not item:
        raise ValueError(f"frozen OSM fixture requires {key}")
    return item
