"""Extract rate limits and quotas from OpenAPI extensions into [limits]."""

from __future__ import annotations

from typing import Any

from lapis_spec.models.lapis import LapisLimits, LapisPlan, LapisQuota, LapisRateLimit
from lapis_spec.models.openapi import OpenAPIDict


def convert_limits(doc: OpenAPIDict) -> LapisLimits | None:
    """Build :class:`LapisLimits` from ``x-rateLimit`` / ``x-quota`` extensions.

    Returns ``None`` if no rate-limit related extensions are found.
    """
    info = doc.get("info", {})
    root_ext = {k: v for k, v in doc.items() if k.startswith("x-")}
    info_ext = {k: v for k, v in info.items() if k.startswith("x-")}
    extensions = {**root_ext, **info_ext}

    rate_limits = extensions.get("x-rateLimit") or extensions.get("x-rate-limit")
    quotas = extensions.get("x-quota") or extensions.get("x-quotas")
    plans_data = extensions.get("x-plans") or extensions.get("x-pricing-plans")

    if not rate_limits and not quotas and not plans_data:
        return None

    limits = LapisLimits()

    if isinstance(rate_limits, dict):
        _parse_rate_limits(rate_limits, limits)
    elif isinstance(rate_limits, list):
        for rl in rate_limits:
            if isinstance(rl, dict):
                parsed = _parse_single_rate(rl)
                if parsed:
                    limits.rates.append(parsed)

    if isinstance(quotas, list):
        for q in quotas:
            if isinstance(q, dict):
                parsed = _parse_single_quota(q)
                if parsed:
                    limits.quotas.append(parsed)

    if isinstance(plans_data, dict):
        for plan_name, plan_info in plans_data.items():
            if isinstance(plan_info, dict):
                plan = _parse_plan(plan_name, plan_info)
                limits.plans.append(plan)

    headers = extensions.get("x-rateLimit-headers")
    if isinstance(headers, list):
        limits.headers = ", ".join(str(h) for h in headers)
    elif isinstance(headers, str):
        limits.headers = headers

    return limits


def _parse_rate_limits(data: dict[str, Any], limits: LapisLimits) -> None:
    if "count" in data and "window" in data:
        parsed = _parse_single_rate(data)
        if parsed:
            limits.rates.append(parsed)
    if "headers" in data:
        limits.headers = data["headers"]
    if "on_exceed" in data:
        limits.on_exceed = data["on_exceed"]
    if "max_body" in data:
        limits.max_body = data["max_body"]
    if "max_upload" in data:
        limits.max_upload = data["max_upload"]


def _parse_single_rate(data: dict[str, Any]) -> LapisRateLimit | None:
    count = data.get("count") or data.get("limit")
    window = data.get("window") or data.get("per") or data.get("period")
    if count is None or window is None:
        return None
    scope = data.get("scope")
    return LapisRateLimit(count=int(count), window=str(window), scope=scope)


def _parse_single_quota(data: dict[str, Any]) -> LapisQuota | None:
    count = data.get("count") or data.get("limit")
    period = data.get("period") or data.get("per")
    unlimited = data.get("unlimited", False)
    if count is None and not unlimited:
        return None
    return LapisQuota(
        count=int(count) if count else None,
        period=str(period) if period else None,
        unlimited=bool(unlimited),
        scope=data.get("scope"),
        description=data.get("description"),
    )


def _parse_plan(name: str, data: dict[str, Any]) -> LapisPlan:
    plan = LapisPlan(name=name)
    for rl in data.get("rates", data.get("rateLimit", [])):
        if isinstance(rl, dict):
            parsed = _parse_single_rate(rl)
            if parsed:
                plan.rates.append(parsed)
    for q in data.get("quotas", data.get("quota", [])):
        if isinstance(q, dict):
            parsed = _parse_single_quota(q)
            if parsed:
                plan.quotas.append(parsed)
    batch = data.get("max_batch")
    if batch is not None:
        plan.max_batch = int(batch)
    return plan
