"""Request validation and coercion helpers for gateway HTTP handlers."""

from __future__ import annotations

import logging
from typing import Any, Mapping, Sequence

from aiohttp import web

_VALIDATION_LOG = logging.getLogger("ember.gateway.validation")


def _require_mapping(field: str, value: object) -> Mapping[str, Any]:
    if not isinstance(value, Mapping):
        raise web.HTTPBadRequest(text=f"{field} must be an object")
    return value


def _require_non_empty_sequence(field: str, value: object) -> Sequence[Any]:
    if (
        not isinstance(value, Sequence)
        or isinstance(value, (str, bytes, bytearray))
        or len(value) == 0
    ):
        raise web.HTTPBadRequest(text=f"{field} must be a non-empty array")
    return value


def _require_non_empty_str(field: str, value: object) -> str:
    if not isinstance(value, str) or not value.strip():
        raise web.HTTPBadRequest(text=f"{field} must be a non-empty string")
    return value.strip()


def _optional_str(value: object, field: str) -> str | None:
    if value is None:
        return None
    if not isinstance(value, str):
        raise web.HTTPBadRequest(text=f"{field} must be a string")
    stripped = value.strip()
    return stripped or None


def _optional_int(value: object, field: str) -> int | None:
    if value is None:
        return None
    if isinstance(value, bool):
        raise web.HTTPBadRequest(text=f"{field} must be an integer")
    try:
        return int(value)
    except (TypeError, ValueError) as exc:
        raise web.HTTPBadRequest(text=f"{field} must be an integer") from exc


def _safe_int(value: Any) -> int:
    try:
        return int(value or 0)
    except (TypeError, ValueError):
        _VALIDATION_LOG.warning("safe_int_coercion value=%r coerced to 0", value)
        return 0


def _ensure_str_list(field: str, value: Any) -> list[str] | None:
    if value is None:
        return None
    if not isinstance(value, Sequence) or isinstance(value, (str, bytes, bytearray)):
        raise web.HTTPBadRequest(text=f"{field} must be an array of non-empty strings")
    parsed: list[str] = []
    for idx, item in enumerate(value):
        if not isinstance(item, str) or not item.strip():
            raise web.HTTPBadRequest(text=f"{field}[{idx}] must be a non-empty string")
        parsed.append(item.strip())
    return parsed


def _to_bool(field: str, value: Any) -> bool | None:
    if value is None:
        return None
    if isinstance(value, bool):
        return value
    raise web.HTTPBadRequest(text=f"{field} must be a boolean")


def _to_int(field: str, value: Any) -> int | None:
    if value is None:
        return None
    if isinstance(value, bool) or not isinstance(value, int):
        raise web.HTTPBadRequest(text=f"{field} must be an integer")
    if value < 0:
        raise web.HTTPBadRequest(text=f"{field} must be >= 0")
    return value


def _to_float(field: str, value: Any) -> float | None:
    if value is None:
        return None
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise web.HTTPBadRequest(text=f"{field} must be a number")
    parsed = float(value)
    if parsed < 0:
        raise web.HTTPBadRequest(text=f"{field} must be >= 0")
    return parsed
