"""Product-independent terrain contracts. No raster or projection dependencies."""

from __future__ import annotations

import math
from dataclasses import dataclass
from typing import Literal, Protocol, runtime_checkable


@dataclass(frozen=True)
class Sample:
    elevation_m: float | None
    status: Literal["valid", "nodata", "out_of_bounds"]

    def __post_init__(self):
        if self.status not in ("valid", "nodata", "out_of_bounds"):
            raise ValueError("invalid sample status")
        if self.status == "valid":
            if self.elevation_m is None or not math.isfinite(self.elevation_m):
                raise ValueError("valid sample requires finite metre elevation")
        elif self.elevation_m is not None:
            raise ValueError("unavailable sample must have null elevation")


@dataclass(frozen=True)
class TerrainMetadata:
    source: str
    product: str | None
    crs: str
    bounds: tuple[float, float, float, float]  # west, south, east, north in native CRS
    horizontal_resolution: tuple[float, float] | None
    horizontal_units: tuple[str, str]
    elevation_unit: str
    vertical_reference: str | None  # None means unknown, never inferred from horizontal CRS
    vertical_reference_verified: bool
    sampling: str
    nodata_policy: str
    provenance: tuple[tuple[str, str], ...] = ()


@runtime_checkable
class ElevationSource(Protocol):
    """Legacy minimal sampler. Inputs always WGS84 latitude, longitude in degrees."""

    def sample(self, latitude: float, longitude: float) -> Sample: ...


@runtime_checkable
class TerrainProvider(ElevationSource, Protocol):
    @property
    def info(self) -> TerrainMetadata: ...


def vertical_reference(value: str) -> str | None:
    """Retain declarations; recognize legacy explicit unknown/pending placeholders."""
    if any(word in value.lower() for word in ("unknown", "pending", "unverified")):
        return None
    return value
