<?php
/**
 * PowerDNS Function Wrappers
 * 
 * These functions provide a simpler interface to the PowerDNS API class
 */

require_once('pdns-api.php');

// PowerDNS API configuration
define('PDNS_API_BASE_URL', 'http://localhost:8081/api/v1');

/**
 * Get the PowerDNS API instance with proper configuration
 *
 * @return PowerDNSAPI
 */
function getPdnsApiInstance() {
    static $pdnsApi = null;
    
    if ($pdnsApi === null) {
        // Get API key
        $apiKey = getPdnsApiKey();
        if (!$apiKey) {
            error_log('PowerDNS API key not found');
        }
        
        $pdnsApi = new PowerDNSAPI(PDNS_API_BASE_URL, $apiKey, 'localhost');
    }
    
    return $pdnsApi;
}

/**
 * Create a new DNS zone for a domain
 *
 * @param string $domain_name Domain name (e.g. example.com)
 * @return array Result with success/error information
 */
function createDnsZone($domain_name) {
    $pdnsApi = getPdnsApiInstance();
    
    // Make sure domain has trailing dot
    $zone_name = ensureTrailingDot($domain_name);
    
    // Create nameserver entries
    $nameservers = [
        'ns1.' . $zone_name,
        'ns2.' . $zone_name
    ];
    
    $result = $pdnsApi->createZone($zone_name, $nameservers, 'Native');
    
    if ($result === false) {
        return [
            'success' => false,
            'error' => $pdnsApi->getLastError()
        ];
    }
    
    // Add default records
    addDefaultDnsRecords($domain_name);
    
    return [
        'success' => true,
        'data' => $result
    ];
}

/**
 * Delete a DNS zone
 *
 * @param string $domain_name Domain name
 * @return array Result with success/error information
 */
function deleteDnsZone($domain_name) {
    $pdnsApi = getPdnsApiInstance();
    
    // Make sure domain has trailing dot
    $zone_name = ensureTrailingDot($domain_name);
    
    $result = $pdnsApi->deleteZone($zone_name);
    
    if (!$result) {
        return [
            'success' => false,
            'error' => $pdnsApi->getLastError()
        ];
    }
    
    return [
        'success' => true
    ];
}

/**
 * Get all records for a domain
 *
 * @param string $domain_name Domain name
 * @return array Result with success/error information and records data
 */
function getDnsRecords($domain_name) {
    $pdnsApi = getPdnsApiInstance();
    
    // Make sure domain has trailing dot
    $zone_name = ensureTrailingDot($domain_name);
    
    $records = $pdnsApi->getRecords($zone_name);
    
    if ($records === false) {
        return [
            'success' => false,
            'error' => $pdnsApi->getLastError()
        ];
    }
    
    // Process records for easier consumption by the application
    $processed_records = [];
    foreach ($records as $record) {
        // Skip SOA records for simpler display
        if ($record['type'] == 'SOA') {
            continue;
        }
        
        foreach ($record['records'] as $content) {
            $processed_records[] = [
                'name' => rtrim($record['name'], '.'),
                'type' => $record['type'],
                'ttl' => $record['ttl'],
                'content' => $content['content'],
                'disabled' => $content['disabled']
            ];
        }
    }
    
    return [
        'success' => true,
        'records' => $processed_records
    ];
}

/**
 * Add a DNS record
 *
 * @param string $domain_name Domain name
 * @param string $name Record name (fully qualified or relative)
 * @param string $type Record type (A, AAAA, CNAME, MX, TXT, etc.)
 * @param string $content Record content
 * @param int $ttl TTL in seconds
 * @param int|null $priority Priority (for MX records)
 * @return array Result with success/error information
 */
function addDnsRecord($domain_name, $name, $type, $content, $ttl = 3600, $priority = null) {
    $pdnsApi = getPdnsApiInstance();
    
    // Make sure domain has trailing dot
    $zone_name = ensureTrailingDot($domain_name);
    
    // Format the record name correctly
    if (substr($name, -strlen($domain_name) - 1) === '.' . $domain_name) {
        // Name already contains domain, just add trailing dot
        $record_name = ensureTrailingDot($name);
    } else if ($name === $domain_name || $name === '@') {
        // Apex record
        $record_name = $zone_name;
    } else {
        // Subdomain, append domain name
        $record_name = $name . '.' . $zone_name;
    }
    
    // For MX records, include priority in content
    $record_content = $content;
    if (strtoupper($type) === 'MX' && $priority !== null) {
        $record_content = $priority . ' ' . $content;
    }
    
    // Make sure CNAME, MX, NS records have trailing dot in content
    if (in_array(strtoupper($type), ['CNAME', 'MX', 'NS', 'SRV'])) {
        $record_content = ensureTrailingDot($record_content);
    }
    
    $result = $pdnsApi->addRecord($zone_name, $record_name, strtoupper($type), $ttl, [$record_content]);
    
    if (!$result) {
        return [
            'success' => false,
            'error' => $pdnsApi->getLastError()
        ];
    }
    
    return [
        'success' => true
    ];
}

/**
 * Delete a DNS record
 *
 * @param string $domain_name Domain name
 * @param string $name Record name
 * @param string $type Record type
 * @return array Result with success/error information
 */
function deleteDnsRecord($domain_name, $name, $type) {
    $pdnsApi = getPdnsApiInstance();
    
    // Make sure domain has trailing dot
    $zone_name = ensureTrailingDot($domain_name);
    
    // Format the record name correctly
    if (substr($name, -strlen($domain_name) - 1) === '.' . $domain_name) {
        // Name already contains domain, just add trailing dot
        $record_name = ensureTrailingDot($name);
    } else if ($name === $domain_name || $name === '@') {
        // Apex record
        $record_name = $zone_name;
    } else {
        // Subdomain, append domain name
        $record_name = $name . '.' . $zone_name;
    }
    
    $result = $pdnsApi->deleteRecord($zone_name, $record_name, strtoupper($type));
    
    if (!$result) {
        return [
            'success' => false,
            'error' => $pdnsApi->getLastError()
        ];
    }
    
    return [
        'success' => true
    ];
}

/**
 * Add default DNS records for a new domain
 *
 * @param string $domain_name Domain name
 * @return void
 */
function addDefaultDnsRecords($domain_name) {
    // Determine server IP address
    $server_ip = $_SERVER['SERVER_ADDR'] ?? '127.0.0.1';
    
    // Add A record for the domain itself
    addDnsRecord($domain_name, '@', 'A', $server_ip);
    
    // Add A record for www subdomain
    addDnsRecord($domain_name, 'www', 'A', $server_ip);
    
    // Add A records for nameservers
    addDnsRecord($domain_name, 'ns1', 'A', $server_ip);
    addDnsRecord($domain_name, 'ns2', 'A', $server_ip);
    
    // Add SOA record
    $soa_content = "ns1.{$domain_name}. admin.{$domain_name}. " . time() . " 10800 3600 604800 3600";
    addDnsRecord($domain_name, '@', 'SOA', $soa_content);
    
    // Add NS records
    addDnsRecord($domain_name, '@', 'NS', "ns1.{$domain_name}.");
    addDnsRecord($domain_name, '@', 'NS', "ns2.{$domain_name}.");
    
    // Add MX record
    addDnsRecord($domain_name, '@', 'MX', "mail.{$domain_name}.", 3600, 10);
    
    // Add A record for mail
    addDnsRecord($domain_name, 'mail', 'A', $server_ip);
}

/**
 * Ensure a domain name has a trailing dot
 *
 * @param string $domain Domain name
 * @return string Domain name with trailing dot
 */
function ensureTrailingDot($domain) {
    if (substr($domain, -1) !== '.') {
        return $domain . '.';
    }
    return $domain;
}

/**
 * Get PowerDNS API key from config file
 * 
 * @return string|null API key if found, null otherwise
 */
function getPdnsApiKey() {
    // In production, this should be retrieved securely
    // For example, from a config file with restricted permissions
    $config_file = '/docker/powerdns/config/pdns.conf';
    if (file_exists($config_file)) {
        $content = file_get_contents($config_file);
        if (preg_match('/api-key=(.+)/', $content, $matches)) {
            return trim($matches[1]);
        }
    }
    return null;
}