"""Pydantic models for privacy networking."""

from __future__ import annotations

from datetime import datetime
from enum import Enum
from pathlib import Path

from pydantic import BaseModel, Field


class PrivacyMode(str, Enum):
    """Privacy routing modes."""

    NONE = "none"
    TOR_PROXY = "tor_proxy"  # SOCKS proxy
    TOR_TRANSPARENT = "tor_transparent"  # Transparent proxy
    VPN = "vpn"
    WIREGUARD = "wireguard"


class PrivacyStatus(str, Enum):
    """Status of a privacy service."""

    RUNNING = "running"
    STOPPED = "stopped"
    STARTING = "starting"
    ERROR = "error"
    BOOTSTRAPPING = "bootstrapping"


# Tor Models


class TorProxyConfig(BaseModel):
    """Tor proxy configuration."""

    socks_port: int = 9050
    """SOCKS5 proxy port."""

    control_port: int = 9051
    """Tor control port for status queries."""

    dns_port: int = 5353
    """DNS port for Tor DNS resolution."""

    trans_port: int = 9040
    """Transparent proxy port (for transparent mode)."""

    transparent: bool = False
    """Enable transparent proxy mode (requires iptables)."""

    exit_nodes: list[str] = Field(default_factory=list)
    """Preferred exit node country codes (e.g., ['US', 'DE'])."""

    exclude_nodes: list[str] = Field(default_factory=list)
    """Country codes to exclude from circuits."""

    bridge_enabled: bool = False
    """Enable bridge mode for censored networks."""

    bridges: list[str] = Field(default_factory=list)
    """Bridge addresses for censorship circumvention."""

    strict_nodes: bool = False
    """Strictly enforce exit/exclude node preferences."""


class TorProxyState(BaseModel):
    """Running Tor proxy state."""

    name: str
    """Unique name for this proxy instance."""

    container_name: str
    """Associated container name."""

    pid: int | None = None
    """Process ID of the Tor daemon."""

    socks_port: int
    """SOCKS proxy port."""

    control_port: int
    """Control port."""

    dns_port: int
    """DNS port."""

    data_dir: Path
    """Tor data directory path."""

    config_file: Path | None = None
    """Path to torrc configuration file."""

    status: PrivacyStatus = PrivacyStatus.STOPPED
    """Current status."""

    started_at: datetime | None = None
    """When the proxy was started."""

    bootstrap_progress: int = 0
    """Bootstrap progress percentage (0-100)."""


class HiddenServiceConfig(BaseModel):
    """Tor hidden service configuration."""

    name: str
    """Unique name for this hidden service."""

    container_name: str
    """Container to expose as hidden service."""

    container_port: int
    """Port inside the container to expose."""

    hidden_service_port: int = 80
    """Port to expose on the .onion address."""

    version: int = 3
    """Hidden service version (2 or 3, v3 recommended)."""


class HiddenServiceState(BaseModel):
    """Running hidden service state."""

    name: str
    """Unique name for this hidden service."""

    onion_address: str | None = None
    """.onion address (set after creation)."""

    container_name: str
    """Associated container name."""

    container_port: int
    """Container port being exposed."""

    hidden_service_port: int
    """Port exposed on the .onion address."""

    data_dir: Path
    """Hidden service data directory."""

    status: PrivacyStatus = PrivacyStatus.STOPPED
    """Current status."""

    created_at: datetime | None = None
    """When the service was created."""


# VPN Models


class VPNProvider(str, Enum):
    """VPN provider types."""

    OPENVPN = "openvpn"
    WIREGUARD = "wireguard"


class VPNGatewayConfig(BaseModel):
    """VPN gateway container configuration."""

    name: str
    """Unique name for this gateway."""

    provider: VPNProvider
    """VPN provider type (openvpn or wireguard)."""

    config_file: Path
    """Path to VPN configuration file."""

    kill_switch: bool = True
    """Block all traffic if VPN connection drops."""

    dns_servers: list[str] = Field(default_factory=lambda: ["1.1.1.1", "1.0.0.1"])
    """DNS servers to use (default: Cloudflare)."""

    route_all_traffic: bool = True
    """Route all container traffic through VPN."""


class VPNGatewayState(BaseModel):
    """Running VPN gateway state."""

    name: str
    """Unique name for this gateway."""

    provider: VPNProvider
    """VPN provider type."""

    container_name: str | None = None
    """Gateway container name (if containerized)."""

    pid: int | None = None
    """Process ID of VPN client."""

    interface: str | None = None
    """VPN network interface (e.g., tun0, wg0)."""

    public_ip: str | None = None
    """Public IP address when connected."""

    status: PrivacyStatus = PrivacyStatus.STOPPED
    """Current status."""

    connected_at: datetime | None = None
    """When the connection was established."""

    config_file: Path | None = None
    """Path to VPN configuration file."""


# WireGuard Models


class WireGuardPeer(BaseModel):
    """WireGuard peer configuration."""

    name: str
    """Peer name for identification."""

    public_key: str
    """Peer's public key."""

    endpoint: str | None = None
    """Peer's endpoint (host:port), optional for peers behind NAT."""

    allowed_ips: list[str] = Field(default_factory=lambda: ["0.0.0.0/0"])
    """IP ranges to route through this peer."""

    persistent_keepalive: int = 25
    """Keepalive interval in seconds (0 to disable)."""

    preshared_key: str | None = None
    """Optional preshared key for additional security."""


class WireGuardInterface(BaseModel):
    """WireGuard interface configuration."""

    private_key: str
    """Interface's private key."""

    address: str
    """Interface IP address with CIDR (e.g., 10.200.0.1/24)."""

    listen_port: int = 51820
    """UDP port for incoming connections."""

    dns: list[str] = Field(default_factory=list)
    """DNS servers for this interface."""

    mtu: int = 1420
    """Interface MTU."""


class WireGuardMeshConfig(BaseModel):
    """WireGuard mesh network configuration."""

    name: str
    """Unique name for this mesh network."""

    subnet: str = "10.200.0.0/24"
    """Subnet for the mesh network."""

    interface_name: str = "wg0"
    """WireGuard interface name."""

    listen_port: int = 51820
    """UDP port for incoming connections."""

    peers: list[WireGuardPeer] = Field(default_factory=list)
    """List of mesh peers."""


class WireGuardMeshState(BaseModel):
    """Running WireGuard mesh state."""

    name: str
    """Unique name for this mesh network."""

    interface: WireGuardInterface | None = None
    """Local interface configuration."""

    peers: list[WireGuardPeer] = Field(default_factory=list)
    """Connected peers."""

    interface_name: str
    """WireGuard interface name."""

    status: PrivacyStatus = PrivacyStatus.STOPPED
    """Current status."""

    config_file: Path | None = None
    """Path to WireGuard configuration file."""

    created_at: datetime | None = None
    """When the mesh was created."""


# DNS Leak Prevention


class DNSLeakConfig(BaseModel):
    """DNS leak prevention configuration."""

    enabled: bool = True
    """Enable DNS leak prevention."""

    dns_servers: list[str] = Field(default_factory=list)
    """Allowed DNS servers (empty = use privacy service DNS)."""

    block_direct_dns: bool = True
    """Block direct DNS queries (port 53) to non-allowed servers."""

    allow_local: bool = False
    """Allow DNS queries to local resolvers (127.0.0.1, etc.)."""
