"""IP allowlist — CIDR validation and access control for Enterprise+.

Stores per-customer IP allowlists in Firestore and provides
middleware-compatible check functions.
"""

from __future__ import annotations

import ipaddress
import logging
from typing import Any

from pydantic import BaseModel, ConfigDict

_log = logging.getLogger(__name__)


class IPAllowlistConfig(BaseModel, frozen=True):
    """IP allowlist configuration stored in customers/{id}."""

    model_config = ConfigDict(strict=True)
    enabled: bool
    cidrs: list[str]


def validate_cidrs(cidrs: list[str]) -> list[str]:
    """Validate each CIDR string. Returns normalized list.

    Raises ValueError on invalid CIDR.
    """
    validated: list[str] = []
    for cidr in cidrs:
        network = ipaddress.ip_network(cidr, strict=False)
        validated.append(str(network))
    return validated


def check_ip_allowed(
    client_ip: str,
    config: IPAllowlistConfig,
) -> bool:
    """Return True if client_ip is within any allowed CIDR.

    Always returns True if allowlist is disabled.
    """
    if not config.enabled:
        return True

    try:
        addr = ipaddress.ip_address(client_ip)
    except ValueError:
        _log.warning("Invalid client IP: %s", client_ip)
        return False

    for cidr in config.cidrs:
        try:
            network = ipaddress.ip_network(cidr, strict=False)
            if addr in network:
                return True
        except ValueError:
            continue

    return False


async def get_ip_allowlist(
    customer_id: str,
) -> IPAllowlistConfig | None:
    """Load IP allowlist from Firestore customers/{customer_id}."""
    from backend.shared.firestore import get_db

    doc = await get_db().collection("customers").document(customer_id).get()
    if not doc.exists:
        return None

    data: dict[str, Any] = doc.to_dict()  # type: ignore[assignment]
    ip_data = data.get("ip_allowlist")
    if ip_data is None:
        return None

    return IPAllowlistConfig(**ip_data)


async def save_ip_allowlist(
    customer_id: str,
    config: IPAllowlistConfig,
) -> None:
    """Write IP allowlist to Firestore customers/{customer_id}."""
    from backend.shared.firestore import get_db

    validated_cidrs = validate_cidrs(config.cidrs)

    await (
        get_db()
        .collection("customers")
        .document(customer_id)
        .update(
            {
                "ip_allowlist": {
                    "enabled": config.enabled,
                    "cidrs": validated_cidrs,
                }
            }
        )
    )
