<?php
// Start session if not already started
if (session_status() == PHP_SESSION_NONE) {
    session_start();
}

// Set longer timeout for large databases
set_time_limit(0); //600 => 10 minutes
ini_set('memory_limit', '1024M');
ini_set('max_execution_time', 0);

// Disable output buffering
if (ob_get_level()) {
    ob_end_clean();
}

// get the config file
include_once("../public/config.php");

//here the db files that include in the file
include("../public/include_dao.php");
//Programsetting
require_once('../models/dao/ProgramsettingsDAO.class.php');
require_once('../models/dto/Programsetting.class.php');
require_once('../models/mysql/ProgramsettingsMySqlDAO.class.php');
require_once('../models/mysql/ext/ProgramsettingsMySqlExtDAO.class.php');

// Check if session has dbname
if (!isset($_SESSION['dbname']) || empty($_SESSION['dbname'])) {
    http_response_code(400);
    die("Database name not found in session. Please login again.");
}

//Programsetting
$Programsetting = new Programsetting();
$ProgramsettingDAO = new ProgramsettingsMySqlDAO();
$ProgramsettingEX = new ProgramsettingsMySqlExtDAO();

$db_user = ConnectionProperty::getUser();
$host = ConnectionProperty::getHost();
$db_password = ConnectionProperty::getPassword();
$generalSettings = $ProgramsettingDAO->load(1);

//getcwd() is to Gets the current working directory
$partition = explode(":", getcwd())[0]; //$generalSettings->partition;
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    //do nothing
} else {//if (!empty(exec("ip link"))) {// unix, linux, mac
    $partition = 0;
}

if ($partition !== $generalSettings->partition) {
    $generalSettings->partition = $partition;
    $ProgramsettingDAO->update($generalSettings);
} else {
    $partition = $generalSettings->partition;
}

$dbname = $_SESSION['dbname'];

// Create backup directory if it doesn't exist
$backup_dir = '../db_backups/temp__manualBackup/';
if (!is_dir($backup_dir)) {
    if (!mkdir($backup_dir, 0755, true)) {
        http_response_code(500);
        die("Failed to create backup directory");
    }
}

// Check compression setting like in backup_tables()
if (!file_exists('../backupset.json')) {
    $data = array('daily' => 5, 'compressed' => 1);
    $json_data = json_encode($data);
    file_put_contents('../backupset.json', $json_data);
}
$json_data = file_get_contents('../backupset.json');
$data = json_decode($json_data, true);
$compressed = isset($data['compressed']) ? $data['compressed'] : 1;

/*Benefits of Compression:
Smaller file sizes: Reduces download time and bandwidth usage
Faster streaming: Smaller chunks mean faster transmission
Less memory usage: Compressed data uses less memory
Better for large databases: Helps prevent timeout issues*/

// Generate unique filename with compression
if ($compressed == 1) {
    $filename = $dbname . '_' . date("Y-m-d_H-i-s") . '.sql.gz';
    $filepath = $backup_dir . $filename;
} else {
    $filename = $dbname . '_' . date("Y-m-d_H-i-s") . '.sql';
    $filepath = $backup_dir . $filename;
}

// Execute mysqldump command following the same pattern as backup_tables()
if (empty($partition) || $partition == "0") {//linux
    ##/usr/bin/mysqldump
    if ($compressed == 1) {
        ##compressed backup
        $command = "mysqldump --user=$db_user --password=$db_password --host=$host --opt --single-transaction --quick --lock-tables=false $dbname | gzip > $filepath 2>/dev/null";
    } else {
        $command = "mysqldump --user=$db_user --password=$db_password --host=$host --opt --single-transaction --quick --lock-tables=false $dbname > $filepath 2>/dev/null";
    }
    
    exec($command, $output, $result);
    
    if ($result !== 0) {
        http_response_code(500);
        die("mysqldump command failed. Please check database connection and permissions.");
    }
    
} else {//localhost
    ## to handle different path for different wamp version
    function find_mysqldump($baseDirs) {
        foreach ($baseDirs as $baseDir) {
            $mysqlPath = $baseDir . '\\bin\\mysql';
            if (!is_dir($mysqlPath))
                continue;

            $versions = scandir($mysqlPath);
            foreach ($versions as $version) {
                if ($version === '.' || $version === '..')
                    continue;

                $dumpPath = $mysqlPath . '\\' . $version . '\\bin\\mysqldump.exe';
                if (file_exists($dumpPath)) {
                    return $dumpPath;
                }
            }
        }
    }

    $pathToWampMysqldump = find_mysqldump([$partition . ':\\wamp', $partition . ':\\wamp64']);
    if (!isset($pathToWampMysqldump) || empty($pathToWampMysqldump)) {
        $pathToWampMysqldump = "$partition:\\wamp\bin\mysql\mysql5.6.17\bin\mysqldump";
    }

    if ($compressed == 1 && file_exists("C:\gzip\bin\gzip.exe")) {
        ##compressed backup
        $command = "$pathToWampMysqldump --user=$db_user --password=$db_password --host=$host --opt --single-transaction --quick --lock-tables=false $dbname | C:\\gzip\\bin\\gzip.exe > $filepath";
    } else {
        $command = "$pathToWampMysqldump --user=$db_user --password=$db_password --host=$host --opt --single-transaction --quick --lock-tables=false $dbname > $filepath";
    }
    
    //i prefer passthru() like system() - same as backup_tables()
    $output = passthru($command); //remove " 2>&1" as it writes warning to backup file
}

// Check if file was created and has content
if (!file_exists($filepath) || filesize($filepath) == 0) {
    http_response_code(500);
    die("Backup file was not created or is empty. Please check database permissions.");
}

// Set headers for file download
if ($compressed == 1) {
    header("Content-type: application/gzip");
} else {
    header("Content-type: application/octet-stream");
}
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . filesize($filepath));
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
header('Connection: close');

// Stream the file to output with smaller chunks and keep-alive
if (file_exists($filepath)) {
    $handle = fopen($filepath, 'rb');
    if ($handle) {
        // Send keep-alive headers periodically
        $chunk_size = 4096; // 4KB chunks (smaller for better streaming)
        $total_sent = 0;
        $file_size = filesize($filepath);
        
        while (!feof($handle)) {
            $chunk = fread($handle, $chunk_size);
            if ($chunk === false) {
                break;
            }
            
            echo $chunk;
            $total_sent += strlen($chunk);
            
            // Flush output every 100KB to prevent timeout
            if ($total_sent % (100 * 1024) < $chunk_size) {
                flush();
                
                // Send a small keep-alive signal
                if (connection_status() != CONNECTION_NORMAL) {
                    break;
                }
            }
        }
        fclose($handle);
    }
    
    // Clean up the temporary file
    unlink($filepath);
} else {
    http_response_code(500);
    die("Backup file not found after creation");
}

exit;
?>