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

/**
 * Cron Controller
 *
 * This controller handles scheduled tasks run via cron job.
 *
 * Usage:
 * Set up cron job with:
 * * * * * * /usr/bin/php /path/to/ncsbillingbk/index.php cron run >> /dev/null 2>&1
 *
 * Or for Windows Task Scheduler:
 * php C:\xampp\htdocs\ncsbillingbk\index.php cron run
 */
class Cron extends CI_Controller {

    public function __construct() {
        parent::__construct();

        // Only allow CLI access for security
        if (!$this->input->is_cli_request()) {
            // Allow web access with a secret key for testing
            $secret_key = $this->input->get('key');
            $expected_key = $this->get_cron_secret_key();
            
            if (empty($secret_key) || $secret_key !== $expected_key) {
                show_error('This script can only be accessed via the command line or with a valid secret key.', 403);
            }
        }

        $this->load->database();
        $this->load->dbutil();
        $this->load->helper('file');
    }

    /**
     * Get cron secret key from config
     */
    private function get_cron_secret_key() {
        // Try to get from config file
        $config_file = APPPATH . 'config/cron_config.php';
        if (file_exists($config_file)) {
            include($config_file);
            if (isset($cron_secret_key) && !empty($cron_secret_key)) {
                return $cron_secret_key;
            }
        }
        
        // Fallback to default (should be changed in production)
        return 'ncs_cron_secret_2024';
    }

    /**
     * Main cron runner - runs all scheduled tasks
     */
    public function run() {
        $this->log_cron("Cron job started");

        // Run daily backup at midnight (or close to it)
        $current_hour = (int) date('H');
        $current_minute = (int) date('i');

        // Run backup at 2 AM daily
        if ($current_hour == 2 && $current_minute < 5) {
            $this->backup();
        }

        // Clean old backups (keep last 30 days)
        if ($current_hour == 3 && $current_minute < 5) {
            $this->cleanup_backups(30);
        }

        $this->log_cron("Cron job completed");

        if ($this->input->is_cli_request()) {
            echo "Cron job executed successfully.\n";
        } else {
            echo json_encode(['status' => 'success', 'message' => 'Cron job executed']);
        }
    }

    /**
     * Manual backup trigger
     */
    public function backup() {
        $this->log_cron("Starting database backup");

        // Create backup directory if it doesn't exist
        $backup_path = FCPATH . 'dbbackup/';
        if (!is_dir($backup_path)) {
            mkdir($backup_path, 0755, true);
        }

        // Generate backup filename with timestamp
        $filename = 'backup_' . date('Y-m-d_H-i-s') . '.sql';
        $filepath = $backup_path . $filename;

        // Get database backup
        $prefs = array(
            'tables'        => array(),  // Empty array means all tables
            'ignore'        => array(),
            'format'        => 'txt',    // txt, gzip, zip
            'filename'      => $filename,
            'add_drop'      => TRUE,
            'add_insert'    => TRUE,
            'newline'       => "\n"
        );

        $backup = $this->dbutil->backup($prefs);

        if ($backup) {
            // Write the backup file
            if (write_file($filepath, $backup)) {
                $this->log_cron("Backup created successfully: $filename");

                // Also create a compressed version
                $zip_filename = str_replace('.sql', '.zip', $filename);
                $zip_filepath = $backup_path . $zip_filename;

                $this->load->library('zip');
                $this->zip->add_data($filename, $backup);
                $this->zip->archive($zip_filepath);

                // Remove the uncompressed file after zipping
                @unlink($filepath);

                $this->log_cron("Compressed backup created: $zip_filename");

                if (!$this->input->is_cli_request()) {
                    return json_encode(['status' => 'success', 'file' => $zip_filename]);
                }
                echo "Backup created: $zip_filename\n";
                return true;
            } else {
                $this->log_cron("ERROR: Failed to write backup file");
                if (!$this->input->is_cli_request()) {
                    return json_encode(['status' => 'error', 'message' => 'Failed to write file']);
                }
                echo "ERROR: Failed to write backup file.\n";
                return false;
            }
        } else {
            $this->log_cron("ERROR: Database backup failed");
            if (!$this->input->is_cli_request()) {
                return json_encode(['status' => 'error', 'message' => 'Backup failed']);
            }
            echo "ERROR: Database backup failed.\n";
            return false;
        }
    }

    /**
     * Clean up old backup files
     * @param int $days Keep backups from last N days
     */
    public function cleanup_backups($days = 30) {
        $this->log_cron("Starting backup cleanup (keeping last $days days)");

        $backup_path = FCPATH . 'dbbackup/';

        if (!is_dir($backup_path)) {
            $this->log_cron("Backup directory does not exist");
            return;
        }

        $files = scandir($backup_path);
        $cutoff_time = time() - ($days * 24 * 60 * 60);
        $deleted_count = 0;

        foreach ($files as $file) {
            if ($file == '.' || $file == '..') continue;

            $filepath = $backup_path . $file;

            // Only process backup files
            if (!preg_match('/^(backup_|uploaded_).+\.(sql|zip)$/', $file)) continue;

            // Check file modification time
            $file_time = filemtime($filepath);

            if ($file_time < $cutoff_time) {
                if (@unlink($filepath)) {
                    $this->log_cron("Deleted old backup: $file");
                    $deleted_count++;
                } else {
                    $this->log_cron("ERROR: Could not delete: $file");
                }
            }
        }

        $this->log_cron("Cleanup complete. Deleted $deleted_count old backup(s)");

        if (!$this->input->is_cli_request()) {
            echo json_encode(['status' => 'success', 'deleted' => $deleted_count]);
        } else {
            echo "Cleanup complete. Deleted $deleted_count old backup(s).\n";
        }
    }

    /**
     * Force backup - can be triggered anytime
     */
    public function force_backup() {
        $this->backup();
    }

    /**
     * Show backup status
     */
    public function status() {
        $backup_path = FCPATH . 'dbbackup/';
        $files = array();
        $total_size = 0;

        if (is_dir($backup_path)) {
            $dir_files = scandir($backup_path);
            foreach ($dir_files as $file) {
                if ($file == '.' || $file == '..') continue;
                if (!preg_match('/\.(sql|zip)$/', $file)) continue;

                $filepath = $backup_path . $file;
                $size = filesize($filepath);
                $total_size += $size;

                $files[] = array(
                    'name' => $file,
                    'size' => $this->format_bytes($size),
                    'date' => date('Y-m-d H:i:s', filemtime($filepath))
                );
            }
        }

        // Sort by date descending
        usort($files, function($a, $b) {
            return strtotime($b['date']) - strtotime($a['date']);
        });

        $result = array(
            'total_backups' => count($files),
            'total_size' => $this->format_bytes($total_size),
            'latest_backups' => array_slice($files, 0, 10)
        );

        if (!$this->input->is_cli_request()) {
            header('Content-Type: application/json');
            echo json_encode($result);
        } else {
            echo "Total backups: " . count($files) . "\n";
            echo "Total size: " . $this->format_bytes($total_size) . "\n\n";
            echo "Latest backups:\n";
            foreach (array_slice($files, 0, 10) as $f) {
                echo "  - {$f['name']} ({$f['size']}) - {$f['date']}\n";
            }
        }
    }

    /**
     * Log cron activities
     */
    private function log_cron($message) {
        $log_path = FCPATH . 'dbbackup/cron.log';
        $timestamp = date('Y-m-d H:i:s');
        $log_entry = "[$timestamp] $message\n";

        // Append to log file
        file_put_contents($log_path, $log_entry, FILE_APPEND | LOCK_EX);
    }

    /**
     * Format bytes to human readable
     */
    private function format_bytes($bytes, $precision = 2) {
        $units = array('B', 'KB', 'MB', 'GB', 'TB');

        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= pow(1024, $pow);

        return round($bytes, $precision) . ' ' . $units[$pow];
    }
}
