"""DNS-specific action classes for reversible DNS configuration changes."""

import json
import subprocess
from pathlib import Path
from typing import Optional
from .actions import BaseAction
from .toolbox import BaseToolBox
from models import DNSProfile


class ApplyDNSProfile(BaseAction):
    """Action to apply a DNS profile with automatic rollback capability."""
    
    def __init__(self, profile: DNSProfile, resolved_conf_path: str = "/etc/systemd/resolved.conf"):
        self.profile = profile
        self.resolved_conf_path = resolved_conf_path
    
    def do(self, toolbox: BaseToolBox) -> dict:
        """Apply DNS profile and save previous config for rollback."""
        # Read current config before applying
        config_before = None
        if toolbox.exists(self.resolved_conf_path):
            config_before = toolbox.read(self.resolved_conf_path)
        
        # Generate new config from profile
        new_config = self._generate_resolved_conf(self.profile)
        
        # Write new config
        toolbox.write(self.resolved_conf_path, new_config)
        
        # Reload systemd-resolved
        toolbox.execute(['systemctl', 'reload-or-restart', 'systemd-resolved'])
        
        return {
            'profile_name': self.profile.name,
            'config_before': config_before,
            'resolved_conf_path': self.resolved_conf_path
        }
    
    @classmethod
    def undo(cls, state: dict, toolbox: BaseToolBox) -> None:
        """Restore previous DNS configuration."""
        config_before = state.get('config_before')
        resolved_conf_path = state.get('resolved_conf_path')
        
        if config_before is not None:
            toolbox.write(resolved_conf_path, config_before)
        else:
            # If there was no config before, restore to minimal default
            default_config = "[Resolve]\nDNS=\nDNSSEC=allow-downgrade\nDNSStubListener=yes\n"
            toolbox.write(resolved_conf_path, default_config)
        
        # Reload systemd-resolved to apply changes
        toolbox.execute(['systemctl', 'reload-or-restart', 'systemd-resolved'])
    
    def _generate_resolved_conf(self, profile: DNSProfile) -> str:
        """Generate systemd-resolved.conf content from DNS profile."""
        from models import DNSType
        
        lines = ["# Generated by Namban DNS Manager", "[Resolve]"]
        dns_servers = []
        is_doh = any(s.dns_type == DNSType.DOH for s in profile.servers)
        is_dot = any(s.dns_type == DNSType.DOT for s in profile.servers)

        for server in profile.servers:
            dns_servers.append(server.primary)
            if server.secondary:
                dns_servers.append(server.secondary)

        if dns_servers:
            lines.append(f"DNS={' '.join(dns_servers)}")
        if is_doh:
            lines.append("DNSOverHTTPS=yes")
        elif is_dot:
            lines.append("DNSOverTLS=opportunistic")

        lines.extend(["DNSSEC=allow-downgrade", "DNSStubListener=yes", "Cache=yes", ""])
        return '\n'.join(lines)


class BackupDNSConfig(BaseAction):
    """Action to backup current DNS configuration."""
    
    def __init__(self, source: str = "/etc/systemd/resolved.conf", 
                 backup_path: Optional[str] = None):
        self.source = source
        self.backup_path = backup_path or "/var/lib/namban/resolved.conf.backup"
    
    def do(self, toolbox: BaseToolBox) -> dict:
        """Backup DNS config through privileged daemon."""
        if toolbox.exists(self.source):
            config_content = toolbox.read(self.source)
        else:
            config_content = ""
        
        # Ensure backup directory exists using toolbox (privileged)
        backup_dir = str(Path(self.backup_path).parent)
        toolbox.mkdir(backup_dir)
        
        # Write backup through toolbox
        toolbox.write(self.backup_path, config_content)
        
        return {
            'source': self.source,
            'backup_path': self.backup_path,
            'original_existed': toolbox.exists(self.source)
        }
    
    @classmethod
    def undo(cls, state: dict, toolbox: BaseToolBox) -> None:
        """Remove backup file through privileged daemon."""
        backup_path = state.get('backup_path')
        if toolbox.exists(backup_path):
            toolbox.remove(backup_path)

