"""Shared input validation helpers."""

from __future__ import annotations

from typing import Any

from ._errors import ConfigurationError

_LOOPBACK_HOSTS = frozenset({"localhost", "127.0.0.1", "[::1]"})


def _validate_redirect_uri_scheme(uri: str) -> None:
    """Reject redirect URIs that use plain HTTP (except localhost loopback).

    Raises:
        ConfigurationError: If the URI uses ``http://`` for a non-loopback host.
    """
    lower = uri.lower()
    if lower.startswith("https://"):
        return
    if not lower.startswith("http://"):
        return  # custom schemes are fine (handled by Adobe IMS validation)

    host_part = lower[len("http://"):]
    authority = host_part.split("/")[0]
    if authority.startswith("["):
        host = authority[: authority.index("]") + 1] if "]" in authority else authority
    else:
        host = authority.split(":")[0]

    if host not in _LOOPBACK_HOSTS:
        raise ConfigurationError(
            f"redirect_uri must use HTTPS for non-localhost hosts, got: {uri}"
        )


def _validate_token_import(data: Any) -> dict[str, Any]:
    """Validate shape and types of an imported token dict.

    Returns the validated dict. Raises ConfigurationError on bad input.
    """
    if not isinstance(data, dict):
        raise ConfigurationError(
            "import_tokens() expects a dict (from export_tokens())."
        )

    access_token = data.get("access_token")
    if access_token is not None and not isinstance(access_token, str):
        raise ConfigurationError(
            f"access_token must be a string or None, got {type(access_token).__name__}."
        )

    refresh_token = data.get("refresh_token")
    if refresh_token is not None and not isinstance(refresh_token, str):
        raise ConfigurationError(
            f"refresh_token must be a string or None, got {type(refresh_token).__name__}."
        )

    expires_at = data.get("expires_at", 0.0)
    if not isinstance(expires_at, (int, float)):
        raise ConfigurationError(
            f"expires_at must be a number, got {type(expires_at).__name__}."
        )

    return data
