//! DNS Integration Module
//!
//! Provides automatic DNS registration and management for provisioned servers.
//! Integrates with CoreDNS for dynamic DNS updates.

pub mod coredns_client;

use std::net::IpAddr;

use anyhow::Result;
pub use coredns_client::{CoreDnsClient, DnsRecord, DnsRecordType};
use tracing::{debug, info, warn};

/// DNS Manager for server DNS registration
pub struct DnsManager {
    client: CoreDnsClient,
    auto_register: bool,
    default_ttl: u32,
}

impl DnsManager {
    /// Create new DNS manager
    pub fn new(coredns_url: String, auto_register: bool, default_ttl: u32) -> Self {
        Self {
            client: CoreDnsClient::new(coredns_url),
            auto_register,
            default_ttl,
        }
    }

    /// Register server in DNS
    pub async fn register_server_dns(&self, hostname: &str, ip: IpAddr) -> Result<()> {
        if !self.auto_register {
            debug!(
                "Auto-register disabled, skipping DNS registration for {}",
                hostname
            );
            return Ok(());
        }

        info!("Registering DNS record: {} -> {}", hostname, ip);

        let record_type = match ip {
            IpAddr::V4(_) => DnsRecordType::A,
            IpAddr::V6(_) => DnsRecordType::AAAA,
        };

        let record = DnsRecord {
            name: hostname.to_string(),
            record_type,
            value: ip.to_string(),
            ttl: self.default_ttl,
        };

        self.client.add_record(record).await?;
        info!("Successfully registered DNS record for {}", hostname);

        Ok(())
    }

    /// Unregister server from DNS
    pub async fn unregister_server_dns(&self, hostname: &str) -> Result<()> {
        if !self.auto_register {
            debug!(
                "Auto-register disabled, skipping DNS cleanup for {}",
                hostname
            );
            return Ok(());
        }

        info!("Unregistering DNS record: {}", hostname);
        self.client.delete_record(hostname).await?;
        info!("Successfully unregistered DNS record for {}", hostname);

        Ok(())
    }

    /// Verify DNS resolution
    pub async fn verify_dns_resolution(&self, hostname: &str) -> Result<bool> {
        debug!("Verifying DNS resolution for {}", hostname);

        match self.client.lookup_record(hostname).await {
            Ok(Some(record)) => {
                info!("DNS resolution verified for {}: {:?}", hostname, record);
                Ok(true)
            }
            Ok(None) => {
                warn!("DNS record not found for {}", hostname);
                Ok(false)
            }
            Err(e) => {
                warn!("DNS resolution failed for {}: {}", hostname, e);
                Err(e)
            }
        }
    }

    /// List all DNS records
    pub async fn list_records(&self) -> Result<Vec<DnsRecord>> {
        self.client.list_records().await
    }

    /// Update existing DNS record
    pub async fn update_dns_record(&self, hostname: &str, new_ip: IpAddr) -> Result<()> {
        info!("Updating DNS record for {} to {}", hostname, new_ip);

        // Delete old record
        self.client.delete_record(hostname).await?;

        // Add new record
        let record_type = match new_ip {
            IpAddr::V4(_) => DnsRecordType::A,
            IpAddr::V6(_) => DnsRecordType::AAAA,
        };

        let record = DnsRecord {
            name: hostname.to_string(),
            record_type,
            value: new_ip.to_string(),
            ttl: self.default_ttl,
        };

        self.client.add_record(record).await?;
        info!("Successfully updated DNS record for {}", hostname);

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_dns_manager_creation() {
        let manager = DnsManager::new("http://localhost:53".to_string(), true, 300);

        assert!(manager.auto_register);
        assert_eq!(manager.default_ttl, 300);
    }

    #[tokio::test]
    async fn test_dns_manager_disabled() {
        let manager = DnsManager::new("http://localhost:53".to_string(), false, 300);

        let ip = "192.168.1.10".parse().unwrap();
        let result = manager.register_server_dns("test-server", ip).await;

        // Should succeed but do nothing when disabled
        assert!(result.is_ok());
    }
}
