from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Mapping

from ..responses import value_correction

DEFAULT_STATUS_MESSAGES = {
    400: "The request data is invalid.",
    401: "Authentication is required to access this resource.",
    403: "You do not have permission to perform this action.",
    404: "The requested resource was not found.",
    409: "The request conflicts with existing data.",
    422: "One or more fields are invalid.",
    429: "Too many requests were sent in a short time.",
    500: "An unexpected error occurred.",
    503: "A required service is temporarily unavailable.",
    504: "A required service took too long to respond.",
}


@dataclass(frozen=True)
class ErrorInfo:
    status_code: int
    code: str
    message: str
    details: list[dict[str, Any]] | None = None
    error_type: str | None = None
    retryable: bool | None = None


def default_message(status_code: int) -> str:
    return DEFAULT_STATUS_MESSAGES.get(status_code, "An unexpected error occurred.")


def clean_message(message: str, *, allow_long_message: bool = False, max_length: int = 240) -> str:
    clean = message.strip().strip('"').strip("'")
    if not clean:
        return ""
    if "\n" in clean:
        return ""
    if len(clean) > max_length and not allow_long_message:
        return ""
    return clean


def safe_client_message(exc: Exception, default: str, *, allow_long_message: bool = False) -> str:
    return clean_message(str(exc), allow_long_message=allow_long_message) or default


def http_detail_mapping(detail: Any) -> Mapping[str, Any] | None:
    return detail if isinstance(detail, Mapping) else None


def extract_request_value(request: Any, attribute: str) -> Any:
    if request is None:
        return None
    return getattr(request, attribute, None)


def extract_request_id(request: Any) -> str | None:
    headers = extract_request_value(request, "headers")
    if headers is None:
        return None
    return headers.get("x-request-id") or headers.get("x-correlation-id")


def coerce_meta(meta: Any | None) -> dict[str, Any]:
    if meta is None:
        return {}
    if isinstance(meta, Mapping):
        raw_meta = dict(meta)
    else:
        dumped = None
        if hasattr(meta, "model_dump"):
            dumped = meta.model_dump()
        elif hasattr(meta, "dict"):
            dumped = meta.dict()
        if not isinstance(dumped, Mapping):
            return {}
        raw_meta = dict(dumped)
    return value_correction({str(key): value for key, value in raw_meta.items() if value is not None})


def build_response_meta(request: Any = None, meta: Any | None = None) -> dict[str, Any]:
    response_meta = coerce_meta(meta)

    request_id = extract_request_id(request)
    if request_id and "request_id" not in response_meta:
        response_meta["request_id"] = request_id

    url = extract_request_value(request, "url")
    path = getattr(url, "path", None) if url else None
    if path and "path" not in response_meta:
        response_meta["path"] = path

    return value_correction(response_meta)
