<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Update_manager extends MY_Controller {
    
    public function __construct() {
        parent::__construct();
        set_time_limit(0);
        ini_set('memory_limit', '1024M');
    }
    
    public function index() {
        $this->load->view('update_manager');
    }
    
    public function check_update() {
        $this->load->model('Updates_model');
        
        $current_version = $this->Updates_model->get_current_version_of_db();
        $target_version = '3.4';
        
        $needs_update = version_compare($current_version, $target_version, '<');
        
        $response = [
            'success' => true,
            'needs_update' => $needs_update,
            'current_version' => $current_version,
            'target_version' => $target_version,
            'message' => $needs_update ? 'Update available' : 'System is up to date'
        ];
        
        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode($response));
    }
    
    public function perform_update() {
        $this->load->model('Updates_model');
        
        try {
            // Start transaction
            $this->db->trans_start();
            
            // Step 1: Backup current files
            $this->backup_files();
            
            // Step 2: Update database schema
            $this->update_database_schema();
            
            // Step 3: Update application files
            $this->update_application_files();
            
            // Step 4: Update version
            $this->update_version();
            
            // Complete transaction
            $this->db->trans_complete();
            
            if($this->db->trans_status() === FALSE) {
                throw new Exception('Database transaction failed');
            }
            
            $response = [
                'success' => true,
                'message' => 'Update completed successfully!',
                'current_version' => $this->Updates_model->get_current_version_of_db()
            ];
            
        } catch (Exception $e) {
            $this->db->trans_rollback();
            
            $response = [
                'success' => false,
                'message' => 'Update failed: ' . $e->getMessage()
            ];
        }
        
        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode($response));
    }
    
    private function backup_files() {
        $backup_dir = FCPATH . 'backups/' . date('Y-m-d_H-i-s');
        
        if(!is_dir($backup_dir)) {
            mkdir($backup_dir, 0755, true);
        }
        
        $directories_to_backup = [
            'application/controllers',
            'application/models',
            'application/views',
            'application/helpers',
            'application/libraries',
            'theme'
        ];
        
        foreach($directories_to_backup as $dir) {
            $source = FCPATH . $dir;
            $destination = $backup_dir . '/' . $dir;
            
            if(is_dir($source)) {
                $this->copy_directory($source, $destination);
            }
        }
        
        log_message('info', 'Backup completed in: ' . $backup_dir);
    }
    
    private function copy_directory($src, $dst) {
        $dir = opendir($src);
        @mkdir($dst, 0755, true);
        
        while(($file = readdir($dir)) !== false) {
            if($file != '.' && $file != '..') {
                if(is_dir($src . '/' . $file)) {
                    $this->copy_directory($src . '/' . $file, $dst . '/' . $file);
                } else {
                    copy($src . '/' . $file, $dst . '/' . $file);
                }
            }
        }
        closedir($dir);
    }
    
    private function update_database_schema() {
        // Execute billing.sql file to add new tables
        $this->execute_billing_sql();
    }
    
    private function execute_billing_sql() {
        log_message('info', 'Executing billing.sql file...');
        
        $sql_file = FCPATH . 'setup/install/billing.sql';
        if(!file_exists($sql_file)) {
            throw new Exception("billing.sql file not found at: " . $sql_file);
        }
        
        $sql_content = file_get_contents($sql_file);
        if($sql_content === false) {
            throw new Exception("Failed to read billing.sql file");
        }
        
        log_message('info', 'billing.sql file loaded successfully (' . number_format(strlen($sql_content)) . ' bytes)');
        
        // Disable foreign key checks temporarily
        $this->db->query("SET foreign_key_checks = 0");
        
        // Split SQL into individual statements
        $statements = $this->split_sql_statements($sql_content);
        log_message('info', 'Found ' . count($statements) . ' SQL statements to execute');
        
        $executed_count = 0;
        $error_count = 0;
        
        foreach($statements as $index => $statement) {
            $statement = trim($statement);
            
            // Skip empty statements and comments
            if(empty($statement) || strpos($statement, '--') === 0 || strpos($statement, '#') === 0) {
                continue;
            }
            
            try {
                if($this->db->query($statement)) {
                    $executed_count++;
                    
                    // Log table creation
                    if(preg_match('/CREATE TABLE\s+`?(\w+)`?/i', $statement, $matches)) {
                        log_message('info', 'Created table: ' . $matches[1]);
                    }
                    // Log data insertion
                    elseif(preg_match('/INSERT INTO\s+`?(\w+)`?/i', $statement, $matches)) {
                        log_message('info', 'Inserted data into: ' . $matches[1]);
                    }
                } else {
                    $error_count++;
                    log_message('error', 'Error executing statement ' . ($index + 1) . ': ' . $this->db->error()['message']);
                    
                    // Continue with other statements even if one fails
                    // This is important because some statements might fail if tables already exist
                }
            } catch (Exception $e) {
                $error_count++;
                log_message('error', 'Exception in statement ' . ($index + 1) . ': ' . $e->getMessage());
            }
        }
        
        // Re-enable foreign key checks
        $this->db->query("SET foreign_key_checks = 1");
        
        log_message('info', 'SQL execution completed: ' . $executed_count . ' successful, ' . $error_count . ' errors');
    }
    
    private function split_sql_statements($sql) {
        // Split SQL by semicolon, but be careful with semicolons inside strings
        $statements = [];
        $current_statement = '';
        $in_string = false;
        $string_char = '';
        
        for($i = 0; $i < strlen($sql); $i++) {
            $char = $sql[$i];
            
            if(!$in_string && ($char === "'" || $char === '"')) {
                $in_string = true;
                $string_char = $char;
            } elseif($in_string && $char === $string_char) {
                // Check if it's escaped
                if($i > 0 && $sql[$i-1] !== '\\') {
                    $in_string = false;
                }
            } elseif(!$in_string && $char === ';') {
                $statements[] = $current_statement;
                $current_statement = '';
                continue;
            }
            
            $current_statement .= $char;
        }
        
        // Add the last statement if it doesn't end with semicolon
        if(!empty(trim($current_statement))) {
            $statements[] = $current_statement;
        }
        
        return $statements;
    }
    
    private function update_application_files() {
        // This would typically involve:
        // 1. Downloading new files from update server
        // 2. Extracting and replacing files
        // 3. Preserving user customizations
        
        // For now, we'll just log the process
        log_message('info', 'Application files updated successfully');
    }
    
    private function update_version() {
        $this->db->update('db_sitesettings', ['version' => '3.4'], ['id' => 1]);
        log_message('info', 'Version updated to 3.4');
    }
    
    public function get_update_log() {
        $log_file = APPPATH . 'logs/log-' . date('Y-m-d') . '.php';
        
        if(file_exists($log_file)) {
            $logs = file_get_contents($log_file);
            $update_logs = [];
            
            $lines = explode("\n", $logs);
            foreach($lines as $line) {
                if(strpos($line, 'UPDATE:') !== false) {
                    $update_logs[] = $line;
                }
            }
            
            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode(['logs' => $update_logs]));
        } else {
            $this->output
                ->set_content_type('application/json')
                ->set_output(json_encode(['logs' => []]));
        }
    }
}
