"""Standalone Configuration Models

This module contains models for managing VPN and FTP configurations
independently of channel-zone relationships. These configurations can be
reused across multiple channels and zones.

Models:
    - StandaloneVPNConfiguration: Reusable VPN configurations
    - StandaloneFTPConfiguration: Reusable FTP configurations
    - ZoneVPNConfiguration: Links zones to VPN configurations
    - ZoneFTPConfiguration: Links zones to FTP configurations
"""

import uuid
from django.db import models
from django.core.validators import RegexValidator, MinValueValidator, MaxValueValidator
from django.utils.translation import gettext_lazy as _

from apps.common.models import BaseModel


class StandaloneVPNConfiguration(BaseModel):
    """
    Standalone VPN configuration that can be reused across multiple channels and zones.
    
    This model allows creating VPN configurations independently of specific
    channel-zone relationships, enabling better configuration management and reuse.
    
    Attributes:
        name (str): Human-readable name for the configuration
        description (str): Optional description
        vpn_type (str): Type of VPN (IPSec, OpenVPN, WireGuard)
        server_address (str): VPN server address
        username/password (str): Authentication credentials
        
    Type-specific fields:
        IPSec: preshared_key, local_subnet, remote_subnet, encryption_algorithm
        OpenVPN: config_file, ca_cert, client_cert, client_key, compression
        WireGuard: private_key, public_key, peer_public_key, endpoint, allowed_ips
    """
    
    VPN_TYPES = [
        ('ipsec', _('IPSec Tunnel')),
        ('openvpn', _('OpenVPN')),
        ('wireguard', _('WireGuard')),
    ]
    
    ENCRYPTION_ALGORITHMS = [
        ('aes128', 'AES-128'),
        ('aes192', 'AES-192'),
        ('aes256', 'AES-256'),
        ('3des', '3DES'),
    ]
    
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False
    )
    name = models.CharField(
        max_length=255,
        verbose_name=_('Configuration Name'),
        help_text=_('Human-readable name for this VPN configuration')
    )
    description = models.TextField(
        blank=True,
        verbose_name=_('Description'),
        help_text=_('Optional description of this VPN configuration')
    )
    vpn_type = models.CharField(
        max_length=20,
        choices=VPN_TYPES,
        verbose_name=_('VPN Type'),
        help_text=_('Type of VPN technology to use')
    )
    server_address = models.CharField(
        max_length=255,
        verbose_name=_('Server Address'),
        help_text=_('VPN server IP address or hostname')
    )
    username = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_('Username'),
        help_text=_('Username for VPN authentication')
    )
    password = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_('Password'),
        help_text=_('Password for VPN authentication')
    )
    
    # IPSec specific fields
    ipsec_preshared_key = models.TextField(
        blank=True,
        verbose_name=_('IPSec Pre-shared Key'),
        help_text=_('Pre-shared key for IPSec authentication')
    )
    ipsec_local_subnet = models.CharField(
        max_length=18,
        blank=True,
        verbose_name=_('Local Subnet'),
        help_text=_('Local network subnet in CIDR notation'),
        validators=[
            RegexValidator(
                regex=r'^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$',
                message=_('Enter a valid subnet in CIDR notation (e.g., 192.168.1.0/24)')
            )
        ]
    )
    ipsec_remote_subnet = models.CharField(
        max_length=18,
        blank=True,
        verbose_name=_('Remote Subnet'),
        help_text=_('Remote network subnet in CIDR notation'),
        validators=[
            RegexValidator(
                regex=r'^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$',
                message=_('Enter a valid subnet in CIDR notation (e.g., 10.0.0.0/24)')
            )
        ]
    )
    ipsec_encryption_algorithm = models.CharField(
        max_length=20,
        choices=ENCRYPTION_ALGORITHMS,
        blank=True,
        verbose_name=_('Encryption Algorithm'),
        help_text=_('Encryption algorithm for IPSec tunnel')
    )
    
    # OpenVPN specific fields
    openvpn_config_file = models.FileField(
        upload_to='vpn/openvpn/configs/',
        blank=True,
        null=True,
        verbose_name=_('OpenVPN Config File'),
        help_text=_('OpenVPN configuration file (.ovpn)')
    )
    openvpn_ca_cert = models.TextField(
        blank=True,
        verbose_name=_('CA Certificate'),
        help_text=_('Certificate Authority certificate content')
    )
    openvpn_client_cert = models.TextField(
        blank=True,
        verbose_name=_('Client Certificate'),
        help_text=_('Client certificate content')
    )
    openvpn_client_key = models.TextField(
        blank=True,
        verbose_name=_('Client Private Key'),
        help_text=_('Client private key content')
    )
    openvpn_compression = models.BooleanField(
        default=False,
        verbose_name=_('Enable Compression'),
        help_text=_('Whether to enable LZO compression')
    )
    
    # WireGuard specific fields
    wireguard_private_key = models.CharField(
        max_length=44,
        blank=True,
        verbose_name=_('Private Key'),
        help_text=_('WireGuard private key (base64 encoded)')
    )
    wireguard_public_key = models.CharField(
        max_length=44,
        blank=True,
        verbose_name=_('Public Key'),
        help_text=_('WireGuard public key (base64 encoded)')
    )
    wireguard_peer_public_key = models.CharField(
        max_length=44,
        blank=True,
        verbose_name=_('Peer Public Key'),
        help_text=_('WireGuard peer public key (base64 encoded)')
    )
    wireguard_endpoint = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_('Endpoint'),
        help_text=_('WireGuard endpoint (IP:port or hostname:port)')
    )
    wireguard_allowed_ips = models.TextField(
        blank=True,
        verbose_name=_('Allowed IPs'),
        help_text=_('Comma-separated list of allowed IP ranges')
    )
    wireguard_persistent_keepalive = models.PositiveIntegerField(
        null=True,
        blank=True,
        validators=[MinValueValidator(1), MaxValueValidator(65535)],
        verbose_name=_('Persistent Keepalive'),
        help_text=_('Keepalive interval in seconds (optional)')
    )
    
    is_active = models.BooleanField(
        default=True,
        verbose_name=_('Is Active'),
        help_text=_('Whether this VPN configuration is active')
    )
    
    class Meta:
        db_table = 'standalone_vpn_configurations'
        ordering = ['name']
        verbose_name = _('Standalone VPN Configuration')
        verbose_name_plural = _('Standalone VPN Configurations')
        indexes = [
            models.Index(fields=['vpn_type', 'is_active']),
            models.Index(fields=['name']),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.get_vpn_type_display()})"
    
    def get_type_specific_config(self):
        """Get configuration specific to the VPN type."""
        if self.vpn_type == 'ipsec':
            return {
                'preshared_key': self.ipsec_preshared_key,
                'local_subnet': self.ipsec_local_subnet,
                'remote_subnet': self.ipsec_remote_subnet,
                'encryption_algorithm': self.ipsec_encryption_algorithm,
            }
        elif self.vpn_type == 'openvpn':
            return {
                'config_file': self.openvpn_config_file,
                'ca_cert': self.openvpn_ca_cert,
                'client_cert': self.openvpn_client_cert,
                'client_key': self.openvpn_client_key,
                'compression': self.openvpn_compression,
            }
        elif self.vpn_type == 'wireguard':
            return {
                'private_key': self.wireguard_private_key,
                'public_key': self.wireguard_public_key,
                'peer_public_key': self.wireguard_peer_public_key,
                'endpoint': self.wireguard_endpoint,
                'allowed_ips': self.wireguard_allowed_ips,
                'persistent_keepalive': self.wireguard_persistent_keepalive,
            }
        return {}


class StandaloneFTPConfiguration(BaseModel):
    """
    Standalone FTP configuration that can be reused across multiple channels and zones.
    
    This model allows creating FTP configurations independently of specific
    channel-zone relationships, enabling better configuration management and reuse.
    
    Attributes:
        name (str): Human-readable name for the configuration
        description (str): Optional description
        host (str): FTP server hostname or IP
        username/password (str): FTP credentials
        port (int): FTP server port
        root_directory (str): Root directory path
        passive_mode (bool): Whether to use passive mode
        ssl_enabled (bool): Whether to use FTPS
        timeout (int): Connection timeout in seconds
    """
    
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False
    )
    name = models.CharField(
        max_length=255,
        verbose_name=_('Configuration Name'),
        help_text=_('Human-readable name for this FTP configuration')
    )
    description = models.TextField(
        blank=True,
        verbose_name=_('Description'),
        help_text=_('Optional description of this FTP configuration')
    )
    host = models.CharField(
        max_length=255,
        verbose_name=_('FTP Host'),
        help_text=_('FTP server hostname or IP address')
    )
    username = models.CharField(
        max_length=100,
        verbose_name=_('Username'),
        help_text=_('Username for FTP authentication')
    )
    password = models.CharField(
        max_length=255,
        verbose_name=_('Password'),
        help_text=_('Password for FTP authentication')
    )
    port = models.PositiveIntegerField(
        default=21,
        validators=[MinValueValidator(1), MaxValueValidator(65535)],
        verbose_name=_('Port'),
        help_text=_('FTP server port number (default: 21)')
    )
    root_directory = models.CharField(
        max_length=500,
        default='/',
        verbose_name=_('Root Directory'),
        help_text=_('Root directory path on the FTP server')
    )
    passive_mode = models.BooleanField(
        default=True,
        verbose_name=_('Passive Mode'),
        help_text=_('Whether to use passive mode for FTP connections')
    )
    ssl_enabled = models.BooleanField(
        default=False,
        verbose_name=_('SSL/TLS Enabled'),
        help_text=_('Whether to use FTPS (FTP over SSL/TLS)')
    )
    timeout = models.PositiveIntegerField(
        default=30,
        validators=[MinValueValidator(5), MaxValueValidator(300)],
        verbose_name=_('Timeout'),
        help_text=_('Connection timeout in seconds')
    )
    
    # Zone-specific attributes
    zone_name = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_('Zone Name'),
        help_text=_('Zone identifier for FTP configuration (e.g., 2005, 2008)')
    )
    verification_number = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_('Verification Number'),
        help_text=_('Verification number for FTP configuration (e.g., 00001, 00002)')
    )
    platform_name = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_('Platform Name'),
        help_text=_('Platform identifier (e.g., CJI, TDF, 2M)')
    )
    
    is_active = models.BooleanField(
        default=True,
        verbose_name=_('Is Active'),
        help_text=_('Whether this FTP configuration is active')
    )
    
    class Meta:
        db_table = 'standalone_ftp_configurations'
        ordering = ['name']
        verbose_name = _('Standalone FTP Configuration')
        verbose_name_plural = _('Standalone FTP Configurations')
        indexes = [
            models.Index(fields=['host', 'port']),
            models.Index(fields=['name']),
            models.Index(fields=['is_active']),
        ]
    
    def __str__(self):
        return f"{self.name} ({self.host}:{self.port})"
    
    def get_connection_string(self):
        """Get FTP connection string."""
        protocol = 'ftps' if self.ssl_enabled else 'ftp'
        return f"{protocol}://{self.username}@{self.host}:{self.port}{self.root_directory}"
    
    def test_connection(self):
        """Test FTP connection (placeholder for actual implementation)."""
        # This would contain actual FTP connection testing logic
        return True


class ZoneVPNConfiguration(BaseModel):
    """
    Links ChannelZone to StandaloneVPNConfiguration.
    
    This model allows zones to have default VPN configurations
    that can be inherited by channels in that zone.
    """
    
    zone = models.ForeignKey(
        'ChannelZone',
        on_delete=models.CASCADE,
        related_name='vpn_configurations',
        verbose_name=_('Zone'),
        help_text=_('The zone this VPN configuration applies to')
    )
    vpn_config = models.ForeignKey(
        StandaloneVPNConfiguration,
        on_delete=models.CASCADE,
        related_name='zone_assignments',
        verbose_name=_('VPN Configuration'),
        help_text=_('The VPN configuration to use for this zone')
    )
    is_default = models.BooleanField(
        default=False,
        verbose_name=_('Is Default'),
        help_text=_('Whether this is the default VPN configuration for the zone')
    )
    priority = models.PositiveIntegerField(
        default=1,
        verbose_name=_('Priority'),
        help_text=_('Priority level (higher number = higher priority)')
    )
    
    class Meta:
        db_table = 'zone_vpn_configurations'
        ordering = ['-priority', 'zone__name']
        verbose_name = _('Zone VPN Configuration')
        verbose_name_plural = _('Zone VPN Configurations')
        unique_together = [['zone', 'vpn_config']]
        indexes = [
            models.Index(fields=['zone', 'is_default']),
            models.Index(fields=['priority']),
        ]
    
    def __str__(self):
        return f"{self.zone.name} - {self.vpn_config.name}"


class ZoneFTPConfiguration(BaseModel):
    """
    Links ChannelZone to StandaloneFTPConfiguration.
    
    This model allows zones to have default FTP configurations
    that can be inherited by channels in that zone.
    """
    
    zone = models.ForeignKey(
        'ChannelZone',
        on_delete=models.CASCADE,
        related_name='ftp_configurations',
        verbose_name=_('Zone'),
        help_text=_('The zone this FTP configuration applies to')
    )
    ftp_config = models.ForeignKey(
        StandaloneFTPConfiguration,
        on_delete=models.CASCADE,
        related_name='zone_assignments',
        verbose_name=_('FTP Configuration'),
        help_text=_('The FTP configuration to use for this zone')
    )
    is_default = models.BooleanField(
        default=False,
        verbose_name=_('Is Default'),
        help_text=_('Whether this is the default FTP configuration for the zone')
    )
    priority = models.PositiveIntegerField(
        default=1,
        verbose_name=_('Priority'),
        help_text=_('Priority level (higher number = higher priority)')
    )
    
    class Meta:
        db_table = 'zone_ftp_configurations'
        ordering = ['-priority', 'zone__name']
        verbose_name = _('Zone FTP Configuration')
        verbose_name_plural = _('Zone FTP Configurations')
        unique_together = [['zone', 'ftp_config']]
        indexes = [
            models.Index(fields=['zone', 'is_default']),
            models.Index(fields=['priority']),
        ]
    
    def __str__(self):
        return f"{self.zone.name} - {self.ftp_config.name}"