"""Pydantic schemas for Webhook endpoints."""
import ipaddress
import socket
import uuid
from datetime import datetime
from urllib.parse import urlparse

from pydantic import BaseModel, ConfigDict, field_validator

# RFC-5735 / RFC-1918 / RFC-3927 — ranges that must never be webhook targets
_BLOCKED_NETWORKS = [
    ipaddress.ip_network("10.0.0.0/8"),
    ipaddress.ip_network("172.16.0.0/12"),
    ipaddress.ip_network("192.168.0.0/16"),
    ipaddress.ip_network("169.254.0.0/16"),   # link-local / AWS IMDS
    ipaddress.ip_network("127.0.0.0/8"),       # loopback
    ipaddress.ip_network("::1/128"),            # IPv6 loopback
    ipaddress.ip_network("fc00::/7"),           # IPv6 ULA
]


def _validate_webhook_url(url: str) -> str:
    """Reject URLs that point to private/reserved addresses (SSRF prevention)."""
    parsed = urlparse(url)
    if parsed.scheme not in ("http", "https"):
        raise ValueError("Webhook URL must use http or https")
    hostname = parsed.hostname
    if not hostname:
        raise ValueError("Webhook URL must include a hostname")

    # Resolve hostname to IP(s) and reject any private/reserved address
    try:
        infos = socket.getaddrinfo(hostname, None)
        for info in infos:
            raw_ip = info[4][0]
            try:
                ip_obj = ipaddress.ip_address(raw_ip)
            except ValueError:
                continue
            for network in _BLOCKED_NETWORKS:
                if ip_obj in network:
                    raise ValueError(
                        f"Webhook URL resolves to a private/reserved address ({raw_ip}) "
                        "and cannot be used"
                    )
    except OSError:
        # DNS resolution failure — allow (will fail at dispatch time)
        pass

    return url


class WebhookConfigCreate(BaseModel):
    name: str
    url: str
    secret: str | None = None
    events: list[str] = []
    is_active: bool = True

    @field_validator("url")
    @classmethod
    def url_must_be_external(cls, v: str) -> str:
        return _validate_webhook_url(v)


class WebhookConfigUpdate(BaseModel):
    name: str | None = None
    url: str | None = None
    secret: str | None = None
    events: list[str] | None = None
    is_active: bool | None = None

    @field_validator("url")
    @classmethod
    def url_must_be_external(cls, v: str | None) -> str | None:
        if v is None:
            return v
        return _validate_webhook_url(v)

class WebhookConfigOut(BaseModel):
    id: uuid.UUID
    name: str
    url: str
    secret: str | None = None  # masked on read
    events: list[str]
    is_active: bool
    created_by: uuid.UUID | None = None
    last_triggered_at: datetime | None = None
    failure_count: int
    created_at: datetime | None = None
    model_config = ConfigDict(from_attributes=True)
