<?php
// Publish Daemon - Background process for automatic publishing
// This script should be run as a cron job or background service

set_time_limit(0);
ini_set('memory_limit', '512M');

require_once '../includes/db.php';
require_once 'publish_generators.php';

class PublishDaemon {
    private $pdo;
    private $running = true;
    private $last_check = 0;
    private $check_interval = 10; // Check every 10 seconds
    
    public function __construct($pdo) {
        $this->pdo = $pdo;
        
        // Handle graceful shutdown
        pcntl_signal(SIGTERM, [$this, 'shutdown']);
        pcntl_signal(SIGINT, [$this, 'shutdown']);
        
        $this->log("Publish daemon started");
    }
    
    public function run() {
        while ($this->running) {
            try {
                pcntl_signal_dispatch();
                
                $this->checkAndPublish();
                
                // Sleep for check interval
                sleep($this->check_interval);
                
            } catch (Exception $e) {
                $this->log("Error in main loop: " . $e->getMessage(), 'ERROR');
                sleep(30); // Wait longer on error
            }
        }
        
        $this->log("Publish daemon stopped");
    }
    
    private function checkAndPublish() {
        $current_time = time();
        
        // Get all active servers that need to be checked
        $stmt = $this->pdo->prepare("
            SELECT * FROM publish_servers 
            WHERE is_active = 1 
            AND (last_publish IS NULL OR UNIX_TIMESTAMP(last_publish) + update_interval <= ?)
            ORDER BY COALESCE(last_publish, '1970-01-01') ASC
        ");
        $stmt->execute([$current_time]);
        $servers = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        foreach ($servers as $server) {
            $this->publishToServer($server);
        }
    }
    
    private function publishToServer($server) {
        $start_time = microtime(true);
        $this->log("Starting publish to server: {$server['name']} (ID: {$server['id']})");
        
        try {
            $event_id = $server['event_id'];
            $data_types = json_decode($server['data_types'], true) ?: [];
            
            if (empty($data_types)) {
                throw new Exception('No data types selected for publishing');
            }
            
            // Connect to FTP
            $connection = ftp_connect($server['host'], $server['port'], 30);
            if (!$connection) {
                throw new Exception('Could not connect to FTP server');
            }
            
            $login = ftp_login($connection, $server['username'], $server['password']);
            if (!$login) {
                ftp_close($connection);
                throw new Exception('FTP login failed');
            }
            
            ftp_pasv($connection, true);
            
            // Create remote directory if needed
            $remote_path = rtrim($server['remote_path'], '/');
            if ($remote_path && !ftp_chdir($connection, $remote_path)) {
                if (!ftp_mkdir($connection, $remote_path)) {
                    ftp_close($connection);
                    throw new Exception('Could not create or access remote directory: ' . $remote_path);
                }
                ftp_chdir($connection, $remote_path);
            }
            
            $uploaded_files = [];
            $temp_dir = sys_get_temp_dir() . '/stylescore_publish_' . $event_id . '_' . time();
            mkdir($temp_dir, 0755, true);
            
            try {
                // Generate and upload files based on selected data types
                foreach ($data_types as $data_type) {
                    $files = $this->generateFiles($data_type, $event_id, $temp_dir);
                    
                    foreach ($files as $file) {
                        if ($this->uploadFile($connection, $file['local'], $file['remote'])) {
                            $uploaded_files[] = $file['remote'];
                            $this->log("Uploaded: {$file['remote']}");
                        } else {
                            $this->log("Failed to upload: {$file['remote']}", 'WARNING');
                        }
                    }
                }
                
                // Update last publish time
                $update_stmt = $this->pdo->prepare("UPDATE publish_servers SET last_publish = NOW() WHERE id = ?");
                $update_stmt->execute([$server['id']]);
                
                $duration = round(microtime(true) - $start_time, 2);
                $message = "Published successfully in {$duration}s. Uploaded " . count($uploaded_files) . " files.";
                
                $this->log($message);
                $this->logPublish($server['id'], 'success', $message, count($uploaded_files), $uploaded_files);
                
            } finally {
                // Cleanup temp directory
                $this->deleteDirectory($temp_dir);
                ftp_close($connection);
            }
            
        } catch (Exception $e) {
            $duration = round(microtime(true) - $start_time, 2);
            $message = "Publish failed after {$duration}s: " . $e->getMessage();
            
            $this->log($message, 'ERROR');
            $this->logPublish($server['id'], 'error', $message, 0, []);
        }
    }
    
    private function generateFiles($data_type, $event_id, $temp_dir) {
        switch ($data_type) {
            case 'html_dashboard':
                return generateHTMLDashboard($event_id, $temp_dir, $this->pdo);
                
            case 'json_data':
                return generateJSONData($event_id, $temp_dir, $this->pdo);
                
            case 'pdf_results':
                return generatePDFResults($event_id, $temp_dir, $this->pdo);
                
            case 'csv_data':
                return generateCSVData($event_id, $temp_dir, $this->pdo);
                
            default:
                throw new Exception("Unknown data type: {$data_type}");
        }
    }
    
    private function uploadFile($connection, $local_file, $remote_file) {
        return ftp_put($connection, $remote_file, $local_file, FTP_BINARY);
    }
    
    private function deleteDirectory($dir) {
        if (!is_dir($dir)) return;
        
        $files = array_diff(scandir($dir), ['.', '..']);
        foreach ($files as $file) {
            $path = $dir . DIRECTORY_SEPARATOR . $file;
            is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
        }
        rmdir($dir);
    }
    
    private function logPublish($server_id, $status, $message, $files_uploaded, $file_list) {
        try {
            $stmt = $this->pdo->prepare("
                INSERT INTO publish_logs (server_id, status, message, files_uploaded, file_list)
                VALUES (?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $server_id,
                $status,
                $message,
                $files_uploaded,
                json_encode($file_list)
            ]);
        } catch (Exception $e) {
            $this->log("Failed to log publish result: " . $e->getMessage(), 'ERROR');
        }
    }
    
    private function log($message, $level = 'INFO') {
        $timestamp = date('Y-m-d H:i:s');
        echo "[{$timestamp}] [{$level}] {$message}\n";
        
        // Also log to file if needed
        $log_file = dirname(__FILE__) . '/logs/publish_daemon.log';
        $log_dir = dirname($log_file);
        
        if (!is_dir($log_dir)) {
            mkdir($log_dir, 0755, true);
        }
        
        file_put_contents($log_file, "[{$timestamp}] [{$level}] {$message}\n", FILE_APPEND | LOCK_EX);
    }
    
    public function shutdown() {
        $this->log("Received shutdown signal");
        $this->running = false;
    }
}

// Command line interface
if (php_sapi_name() === 'cli') {
    echo "StyleScore Publish Daemon\n";
    echo "========================\n\n";
    
    if (isset($argv[1])) {
        switch ($argv[1]) {
            case 'start':
                echo "Starting publish daemon...\n";
                $daemon = new PublishDaemon($pdo);
                $daemon->run();
                break;
                
            case 'test':
                echo "Testing publish system...\n";
                $daemon = new PublishDaemon($pdo);
                
                // Get first active server for testing
                $stmt = $pdo->prepare("SELECT * FROM publish_servers WHERE is_active = 1 LIMIT 1");
                $stmt->execute();
                $server = $stmt->fetch(PDO::FETCH_ASSOC);
                
                if ($server) {
                    echo "Testing server: {$server['name']}\n";
                    $daemon->publishToServer($server);
                } else {
                    echo "No active servers found for testing\n";
                }
                break;
                
            case 'status':
                echo "Checking publish server status...\n";
                $stmt = $pdo->query("
                    SELECT ps.name, ps.is_active, ps.last_publish, ps.update_interval,
                           COUNT(pl.id) as log_count,
                           SUM(CASE WHEN pl.status = 'success' THEN 1 ELSE 0 END) as success_count,
                           SUM(CASE WHEN pl.status = 'error' THEN 1 ELSE 0 END) as error_count
                    FROM publish_servers ps
                    LEFT JOIN publish_logs pl ON ps.id = pl.server_id AND pl.publish_time >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
                    GROUP BY ps.id
                    ORDER BY ps.name
                ");
                $servers = $stmt->fetchAll(PDO::FETCH_ASSOC);
                
                foreach ($servers as $server) {
                    echo sprintf(
                        "%-30s | %s | Last: %-19s | Success: %d | Errors: %d\n",
                        $server['name'],
                        $server['is_active'] ? 'Active  ' : 'Inactive',
                        $server['last_publish'] ?: 'Never',
                        $server['success_count'],
                        $server['error_count']
                    );
                }
                break;
                
            default:
                echo "Unknown command: {$argv[1]}\n";
                break;
        }
    } else {
        echo "Usage: php publish_daemon.php [start|test|status]\n";
        echo "\n";
        echo "Commands:\n";
        echo "  start   - Start the publish daemon (runs continuously)\n";
        echo "  test    - Test publishing to the first active server\n";
        echo "  status  - Show status of all publish servers\n";
        echo "\n";
        echo "To run as a background service:\n";
        echo "  nohup php publish_daemon.php start > /dev/null 2>&1 &\n";
        echo "\n";
        echo "To add to crontab (check every minute):\n";
        echo "  * * * * * /usr/bin/php " . __FILE__ . " start\n";
    }
} else {
    echo "This script must be run from command line\n";
}
?>
