<?php
/**
 * DecentraBrowser Central Registration Server
 * 
 * This script handles domain registration, availability checks, and DDNS synchronization
 * for the DecentraBrowser network.
 * 
 * Endpoints:
 *   - cent.php?check={domain} - Check if a domain exists
 *   - cent.php?register={domain}&ip={ip}&port={port}&title={title} - Register a new domain
 *   - cent.php?unregister={domain} - Unregister a domain
 *   - cent.php?sync=1&domains={json_domains} - Synchronize domains
 *   - cent.php?list=1 - List all registered domains
 */

// Configuration
$config = [
    'db_file' => 'decentra_domains.json',     // File to store domain data
    'log_file' => 'decentra_server.log',      // Log file
    'max_domains_per_ip' => 10000,               // Maximum domains per IP
    'reserved_domains' => ['admin', 'system', 'central', 'registry'] // Reserved prefixes
];

// Initialize response
header('Content-Type: application/json');
$response = ['success' => false];

// Initialize domains database
$domains = [];
if (file_exists($config['db_file'])) {
    $domains_json = file_get_contents($config['db_file']);
    $domains = json_decode($domains_json, true) ?: [];
}

// Create log function
function log_message($message) {
    global $config;
    $timestamp = date('Y-m-d H:i:s');
    $log_entry = "[$timestamp] $message\n";
    file_put_contents($config['log_file'], $log_entry, FILE_APPEND);
}

// Save domains to file
function save_domains($domains) {
    global $config;
    $domains_json = json_encode($domains, JSON_PRETTY_PRINT);
    file_put_contents($config['db_file'], $domains_json);
}

// Check if a domain name format is valid
function is_valid_domain_format($domain) {
    // Check for proper format: prefix.main.suffix.domain
    $parts = explode('.', $domain);
    return (count($parts) === 4 && $parts[3] === 'domain');
}

// Check if a domain prefix is reserved
function is_reserved_prefix($domain) {
    global $config;
    $parts = explode('.', $domain);
    return in_array(strtolower($parts[0]), $config['reserved_domains']);
}

// Check if an IP has too many domains
function has_too_many_domains($ip) {
    global $domains, $config;
    
    $count = 0;
    foreach ($domains as $domain) {
        if ($domain['ip'] === $ip) {
            $count++;
        }
    }
    
    return $count >= $config['max_domains_per_ip'];
}

// DOMAIN AVAILABILITY CHECK
if (isset($_GET['check'])) {
    $domain = $_GET['check'];
    
    // Validate domain format
    if (!is_valid_domain_format($domain)) {
        $response = [
            'available' => false,
            'reason' => 'Invalid domain format. Must be prefix.main.suffix.domain'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if domain is reserved
    if (is_reserved_prefix($domain)) {
        $response = [
            'available' => false,
            'reason' => 'Domain prefix is reserved'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if domain exists
    if (isset($domains[$domain])) {
        $response = [
            'available' => false,
            'reason' => 'Domain already registered'
        ];
    } else {
        $response = [
            'available' => true,
            'message' => 'Domain is available'
        ];
    }
    
    log_message("Domain check for '$domain': " . ($response['available'] ? 'available' : 'unavailable'));
    echo json_encode($response);
    exit;
}

// DOMAIN REGISTRATION
if (isset($_GET['register'])) {
    $domain = $_GET['register'];
    $ip = $_GET['ip'] ?? $_SERVER['REMOTE_ADDR'];
    $port = (int)($_GET['port'] ?? 8844);
    $title = $_GET['title'] ?? '';
    
    // Validate domain format
    if (!is_valid_domain_format($domain)) {
        $response = [
            'success' => false,
            'error' => 'Invalid domain format. Must be prefix.main.suffix.domain'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if domain is reserved
    if (is_reserved_prefix($domain)) {
        $response = [
            'success' => false,
            'error' => 'Domain prefix is reserved'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if domain already exists
    if (isset($domains[$domain])) {
        $response = [
            'success' => false,
            'error' => 'Domain already registered',
            'status' => 'exists'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if IP has too many domains
    if (has_too_many_domains($ip)) {
        $response = [
            'success' => false,
            'error' => 'Maximum domains per IP reached',
            'status' => 'limit_reached'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Register the domain
    $domains[$domain] = [
        'ip' => $ip,
        'port' => $port,
        'title' => $title,
        'registered' => date('Y-m-d H:i:s'),
        'last_seen' => date('Y-m-d H:i:s')
    ];
    
    save_domains($domains);
    
    $response = [
        'success' => true,
        'message' => 'Domain registered successfully',
        'domain' => $domain
    ];
    
    log_message("Registered domain '$domain' with IP '$ip:$port'");
    echo json_encode($response);
    exit;
}

// DOMAIN UNREGISTRATION
if (isset($_GET['unregister'])) {
    $domain = $_GET['unregister'];
    $client_ip = $_SERVER['REMOTE_ADDR'];
    
    // Validate domain format
    if (!is_valid_domain_format($domain)) {
        $response = [
            'success' => false,
            'error' => 'Invalid domain format. Must be prefix.main.suffix.domain'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if domain exists
    if (!isset($domains[$domain])) {
        $response = [
            'success' => false,
            'error' => 'Domain not found',
            'status' => 'not_found'
        ];
        echo json_encode($response);
        exit;
    }
    
    // Check if request is from the domain owner (by IP)
    // Allow override with force parameter for administrative purposes
    $force_unregister = isset($_GET['force']) && $_GET['force'] == 1;
    $domain_ip = $domains[$domain]['ip'];
    
    if ($client_ip !== $domain_ip && !$force_unregister) {
        $response = [
            'success' => false,
            'error' => 'Unauthorized: Only the domain owner can unregister this domain',
            'status' => 'unauthorized',
            'client_ip' => $client_ip,
            'domain_ip' => $domain_ip
        ];
        echo json_encode($response);
        exit;
    }
    
    // Unregister the domain
    unset($domains[$domain]);
    save_domains($domains);
    
    $response = [
        'success' => true,
        'message' => 'Domain unregistered successfully',
        'domain' => $domain
    ];
    
    log_message("Unregistered domain '$domain' by IP '$client_ip'");
    echo json_encode($response);
    exit;
}

// DOMAIN LIST REQUEST
if (isset($_GET['list'])) {
    $response = [
        'success' => true,
        'count' => count($domains),
        'domains' => $domains
    ];
    
    log_message("Domain list requested, returning " . count($domains) . " domains");
    echo json_encode($response);
    exit;
}

// DOMAIN SYNCHRONIZATION
if (isset($_GET['sync'])) {
    $client_domains_json = $_POST['domains'] ?? $_GET['domains'] ?? '{}';
    $client_domains = json_decode($client_domains_json, true) ?: [];
    
    // Update server with client domains
    $domains_added = 0;
    $domains_updated = 0;
    
    foreach ($client_domains as $domain => $info) {
        if (!isset($domains[$domain])) {
            // Add new domain
            $domains[$domain] = $info;
            $domains_added++;
            log_message("Added new domain from sync: $domain");
        } else {
            // Update existing domain
            $domains[$domain]['last_seen'] = date('Y-m-d H:i:s');
            
            // Update IP and port if they've changed
            if ($domains[$domain]['ip'] !== $info['ip'] || $domains[$domain]['port'] !== $info['port']) {
                $domains[$domain]['ip'] = $info['ip'];
                $domains[$domain]['port'] = $info['port'];
                $domains_updated++;
                log_message("Updated domain from sync: $domain");
            }
        }
    }
    
    save_domains($domains);
    
    // Return complete domain list to client
    $response = [
        'success' => true,
        'added' => $domains_added,
        'updated' => $domains_updated,
        'count' => count($domains),
        'domains' => $domains
    ];
    
    log_message("Sync completed. Added: $domains_added, Updated: $domains_updated");
    echo json_encode($response);
    exit;
}

// If we reach here, no valid action was specified
$response = [
    'success' => false,
    'error' => 'Invalid request',
    'endpoints' => [
        'check' => 'cent.php?check={domain}',
        'register' => 'cent.php?register={domain}&ip={ip}&port={port}&title={title}',
        'unregister' => 'cent.php?unregister={domain}',
        'sync' => 'cent.php?sync=1&domains={json_domains}',
        'list' => 'cent.php?list=1'
    ]
];

echo json_encode($response);