<?php
/**
 * CMTC Tech Solution - Database Connection
 * Database: smart_dine_cloud_db
 * Driver: PDO (Prepared Statements enabled)
 */

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// Load .env file if it exists
if (file_exists(__DIR__ . '/.env')) {
    $lines = file(__DIR__ . '/.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        $line = trim($line);
        if (empty($line) || strpos($line, '#') === 0) {
            continue;
        }
        if (strpos($line, '=') !== false) {
            list($name, $value) = explode('=', $line, 2);
            $name = trim($name);
            $value = trim($value);
            // Remove optional surrounding quotes
            $value = preg_replace('/^[\'"]|[\'"]$/', '', $value);
            
            if (!array_key_exists($name, $_SERVER) && !array_key_exists($name, $_ENV)) {
                putenv("{$name}={$value}");
                $_ENV[$name] = $value;
                $_SERVER[$name] = $value;
            }
        }
    }
}

$db_host = getenv('DB_HOST') ?: 'localhost';
$db_port = getenv('DB_PORT') ?: '3306';
/*
$db_user = getenv('DB_USER') !== false ? getenv('DB_USER') : 'root';
$db_pass = getenv('DB_PASS') !== false ? getenv('DB_PASS') : '';
$db_name = getenv('DB_NAME') ?: 'smart_dine_cloud_db';
*/
$db_user = getenv('DB_USER') !== false ? getenv('DB_USER') : 'sme_os';
$db_pass = getenv('DB_PASS') !== false ? getenv('DB_PASS') : '@smetech69';
$db_name = getenv('DB_NAME') ?: 'sme_os';


$db_debug = filter_var(getenv('DB_DEBUG'), FILTER_VALIDATE_BOOLEAN);

try {
    $pdo = new PDO(
        "mysql:host={$db_host};port={$db_port};dbname={$db_name};charset=utf8mb4",
        $db_user,
        $db_pass,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false,
        ]
    );
    // Explicitly enforce UTF-8 connection encoding to resolve scrambled Thai text in local environments
    $pdo->exec("SET NAMES utf8mb4");

    // 1. plans Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `plans` (
        `id` INT AUTO_INCREMENT PRIMARY KEY,
        `name` VARCHAR(100) NOT NULL,
        `price` DECIMAL(10, 2) NOT NULL,
        `limit_tables` INT NOT NULL,
        `description` TEXT NOT NULL
    ) ENGINE=InnoDB;");

    // 2. tenants Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `tenants` (
        `store_id` INT AUTO_INCREMENT PRIMARY KEY,
        `store_name` VARCHAR(255) NOT NULL,
        `address` TEXT,
        `category` VARCHAR(100),
        `plan_id` INT,
        `status` VARCHAR(50) DEFAULT 'active',
        `promo_banner` VARCHAR(255),
        `policy_text` TEXT,
        `custom_logo_url` VARCHAR(255)
    ) ENGINE=InnoDB;");

    try { $pdo->exec("ALTER TABLE `tenants` ADD COLUMN `store_banner_url` VARCHAR(255) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `tenants` ADD COLUMN `phone` VARCHAR(50) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `tenants` ADD COLUMN `line_id` VARCHAR(100) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `tenants` ADD COLUMN `trial_ends_at` DATETIME DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `shops` ADD COLUMN `trial_ends_at` DATETIME DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("UPDATE `tenants` SET `trial_ends_at` = DATE_ADD(NOW(), INTERVAL CASE WHEN plan_id = 3 THEN 7 ELSE 14 END DAY) WHERE `trial_ends_at` IS NULL AND `status` != 'active'"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `menus` ADD COLUMN `description` TEXT DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `menus` ADD COLUMN `spice_options` VARCHAR(255) DEFAULT 'เผ็ดปกติ,ไม่เผ็ด,เผ็ดน้อย,เผ็ดมาก'"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `menus` ADD COLUMN `unit` VARCHAR(50) DEFAULT 'จาน'"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `order_items` ADD COLUMN `note` VARCHAR(255) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `order_items` ADD COLUMN `spice_level` VARCHAR(50) DEFAULT NULL"); } catch (PDOException $e) {}

    // 3. users Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `users` (
        `id` INT AUTO_INCREMENT PRIMARY KEY,
        `username` VARCHAR(150) NOT NULL UNIQUE,
        `password` VARCHAR(255) NOT NULL,
        `role` ENUM('super_admin', 'store_admin') NOT NULL,
        `store_id` INT DEFAULT NULL,
        FOREIGN KEY (`store_id`) REFERENCES `tenants`(`store_id`) ON DELETE CASCADE
    ) ENGINE=InnoDB;");

    // Add foreign key constraint to tenants plan_id if not present
    try {
        $pdo->exec("ALTER TABLE `tenants` ADD CONSTRAINT `fk_tenants_plan` FOREIGN KEY (`plan_id`) REFERENCES `plans`(`id`) ON DELETE SET NULL");
    } catch (PDOException $e) {
        // FK probably already exists
    }

    // 4. menus Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `menus` (
        `menu_id` INT AUTO_INCREMENT PRIMARY KEY,
        `store_id` INT NOT NULL,
        `name` VARCHAR(255) NOT NULL,
        `price` DECIMAL(10, 2) NOT NULL,
        `category` VARCHAR(100) NOT NULL,
        `image_url` VARCHAR(255),
        `is_available` TINYINT(1) DEFAULT 1,
        `sort_order` INT DEFAULT 0,
        FOREIGN KEY (`store_id`) REFERENCES `tenants`(`store_id`) ON DELETE CASCADE
    ) ENGINE=InnoDB;");

    try { $pdo->exec("ALTER TABLE `menus` ADD COLUMN `sort_order` INT DEFAULT 0"); } catch (PDOException $e) {}

    // 4.1. categories Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `categories` (
        `id` INT AUTO_INCREMENT PRIMARY KEY,
        `store_id` INT NOT NULL,
        `name` VARCHAR(100) NOT NULL,
        `sort_order` INT DEFAULT 0,
        `is_active` TINYINT(1) DEFAULT 1,
        FOREIGN KEY (`store_id`) REFERENCES `tenants`(`store_id`) ON DELETE CASCADE
    ) ENGINE=InnoDB;");

    // Auto-seed categories from existing menus if missing
    try {
        $pdo->exec("INSERT INTO `categories` (store_id, name, sort_order, is_active)
            SELECT DISTINCT m.store_id, m.category, 0, 1
            FROM `menus` m
            WHERE m.category IS NOT NULL AND TRIM(m.category) != ''
            AND NOT EXISTS (
                SELECT 1 FROM `categories` c WHERE c.store_id = m.store_id AND c.name = m.category
            )");
    } catch (PDOException $e) {}

    // 5. tables_qr Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `tables_qr` (
        `table_id` INT AUTO_INCREMENT PRIMARY KEY,
        `store_id` INT NOT NULL,
        `table_number` VARCHAR(50) NOT NULL,
        `qr_code_url` VARCHAR(255) NOT NULL,
        `qr_token` VARCHAR(64) DEFAULT NULL,
        FOREIGN KEY (`store_id`) REFERENCES `tenants`(`store_id`) ON DELETE CASCADE
    ) ENGINE=InnoDB;");

    try {
        $pdo->exec("ALTER TABLE `tables_qr` ADD COLUMN `qr_token` VARCHAR(64) DEFAULT NULL");
    } catch (PDOException $e) {}
    // Static QR + Guest Authenticator: track table occupancy state and current guest name
    try { $pdo->exec("ALTER TABLE `tables_qr` ADD COLUMN `table_status` ENUM('available','occupied') NOT NULL DEFAULT 'available'"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `tables_qr` ADD COLUMN `table_guest_name` VARCHAR(100) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `tables_qr` ADD COLUMN `session_token` VARCHAR(64) DEFAULT NULL"); } catch (PDOException $e) {}

    try { $pdo->exec("ALTER TABLE `orders` ADD COLUMN `payment_method` VARCHAR(50) DEFAULT 'cash'"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `orders` ADD COLUMN `is_paid` TINYINT(1) DEFAULT 0"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `orders` ADD COLUMN `slip_url` VARCHAR(255) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `orders` ADD COLUMN `voucher` VARCHAR(50) DEFAULT NULL"); } catch (PDOException $e) {}
    try { $pdo->exec("ALTER TABLE `orders` MODIFY COLUMN `voucher` VARCHAR(50) NULL"); } catch (PDOException $e) {}

    // Create orders table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `orders` (
        `id` INT AUTO_INCREMENT PRIMARY KEY,
        `store_id` INT NOT NULL,
        `table_number` VARCHAR(50) NOT NULL,
        `status` ENUM('pending', 'preparing', 'ready', 'served', 'completed', 'cancelled') DEFAULT 'pending',
        `payment_method` VARCHAR(50) DEFAULT 'cash',
        `is_paid` TINYINT(1) DEFAULT 0,
        `slip_url` VARCHAR(255) DEFAULT NULL,
        `voucher` VARCHAR(50) DEFAULT NULL,
        `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (`store_id`) REFERENCES `tenants`(`store_id`) ON DELETE CASCADE
    ) ENGINE=InnoDB;");

    // Create order_items table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `order_items` (
        `id` INT AUTO_INCREMENT PRIMARY KEY,
        `order_id` INT NOT NULL,
        `menu_id` INT DEFAULT NULL,
        `quantity` INT NOT NULL DEFAULT 1,
        `price` DECIMAL(10, 2) NOT NULL,
        FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON DELETE CASCADE,
        FOREIGN KEY (`menu_id`) REFERENCES `menus`(`menu_id`) ON DELETE SET NULL
    ) ENGINE=InnoDB;");

    // 6. payments Table
    $pdo->exec("CREATE TABLE IF NOT EXISTS `payments` (
        `payment_id` INT AUTO_INCREMENT PRIMARY KEY,
        `store_id` INT NOT NULL,
        `plan_id` INT NOT NULL,
        `amount` DECIMAL(10, 2) NOT NULL,
        `slip_url` VARCHAR(255) DEFAULT NULL,
        `status` ENUM('pending', 'approved', 'rejected') DEFAULT 'pending',
        `note` TEXT DEFAULT NULL,
        `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (`store_id`) REFERENCES `tenants`(`store_id`) ON DELETE CASCADE,
        FOREIGN KEY (`plan_id`) REFERENCES `plans`(`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB;");

    // Seed default plans if empty
    $checkPlans = $pdo->query("SELECT COUNT(*) FROM `plans`")->fetchColumn();
    if ($checkPlans == 0) {
        $pdo->exec("INSERT INTO `plans` (id, name, price, limit_tables, description) VALUES
            (1, 'Starter', 490.00, 10, 'เหมาะสำหรับร้านเริ่มต้นขนาดเล็ก พร้อมระบบจัดการโต๊ะและคิวพื้นฐาน'),
            (2, 'Standard', 990.00, 30, 'เหมาะสำหรับร้านขนาดกลาง บริหารจัดการระบบอาหารและคิวได้คล่องตัวขึ้น'),
            (3, 'Premium', 1590.00, 100, 'ร้านค้าขนาดใหญ่ บริหารโต๊ะ บุฟเฟ่ต์ และเครื่องมือการตลาดครบครัน')");
    }

    // Seed default super admin user if empty
    $checkSuperAdmin = $pdo->query("SELECT COUNT(*) FROM `users` WHERE `role` = 'super_admin'")->fetchColumn();
    if ($checkSuperAdmin == 0) {
        $hashed_admin_pass = password_hash('admin1234', PASSWORD_DEFAULT);
        $stmt_sa = $pdo->prepare("INSERT INTO `users` (username, password, role, store_id) VALUES ('admin', :password, 'super_admin', NULL)");
        $stmt_sa->execute([':password' => $hashed_admin_pass]);
    }

    // Seed default demo tenant and store admin if empty
    $checkTenants = $pdo->query("SELECT COUNT(*) FROM `tenants`")->fetchColumn();
    if ($checkTenants == 0) {
        $pdo->exec("INSERT INTO `tenants` (store_id, store_name, address, category, plan_id, status, promo_banner, policy_text, custom_logo_url) VALUES
            (1, 'ร้านกะเพรา CMTC Tech', 'วิทยาลัยเทคนิคเชียงใหม่ อาคาร 3 ชั้น 1', 'อาหารตามสั่ง', 2, 'active', 'แถมฟรีไข่ดาวทุกเมนูเมื่อสั่งผ่านเว็บ!', 'การยกเลิกออเดอร์ต้องแจ้งพนักงานภายใน 3 นาทีหลังการสั่งซื้อ', 'https://upload.wikimedia.org/wikipedia/th/thumb/b/b5/Vocational_Education_Commission_logo.svg/200px-Vocational_Education_Commission_logo.svg.png')");
        
        $hashed_store_pass = password_hash('store1234', PASSWORD_DEFAULT);
        $stmt_st = $pdo->prepare("INSERT INTO `users` (username, password, role, store_id) VALUES ('store1', :password, 'store_admin', 1)");
        $stmt_st->execute([':password' => $hashed_store_pass]);
        
        // Seed default menus for tenant 1
        $pdo->exec("INSERT INTO `menus` (store_id, name, price, category, image_url, is_available) VALUES
            (1, 'ข้าวกะเพราหมูสับไข่ดาว (สูตรดั้งเดิม)', 50.00, 'อาหารจานเดียว', 'https://images.unsplash.com/photo-1512058564366-18510be2db19?w=600&auto=format&fit=crop&q=60', 1),
            (1, 'ชาไทยเย็นสูตรเข้มข้น CMTC', 30.00, 'เครื่องดื่ม', 'https://images.unsplash.com/photo-1544787219-7f47ccb76574?w=600&auto=format&fit=crop&q=60', 1)");

        // Seed default tables for tenant 1 — static QR URLs (no token in URL; physical stickers never need reprinting)
        $pdo->exec("INSERT INTO `tables_qr` (store_id, table_number, qr_code_url, table_status) VALUES
            (1, 'Table 1', 'menu.php?store_id=1&table=1', 'available'),
            (1, 'Table 2', 'menu.php?store_id=1&table=2', 'available')");
    }
} catch (PDOException $e) {
    error_log("Database Connection Error: " . $e->getMessage());
    
    // Display detailed error in debug mode
    $error_details = '';
    if ($db_debug) {
        $error_details = "<div style='margin-top: 15px; text-align: left; background: #333; color: #fff; padding: 15px; font-family: monospace; font-size: 13px; border-radius: 4px;'>
            <strong>Debug Exception Details:</strong><br>" . 
            htmlspecialchars($e->getMessage()) . "<br><br>" .
            "<strong>Connection Parameters:</strong><br>" .
            "Host: " . htmlspecialchars($db_host) . "<br>" .
            "Port: " . htmlspecialchars($db_port) . "<br>" .
            "User: " . htmlspecialchars($db_user) . "<br>" .
            "Database: " . htmlspecialchars($db_name) . "
        </div>";
    }

    die("<div style='font-family: \"Sarabun\", \"Inter\", sans-serif; text-align: center; margin-top: 80px; padding: 25px; border: 2px solid #BD2130; background-color: #FFF0F0; max-width: 600px; margin-left: auto; margin-right: auto;'>
        <h2 style='color: #BD2130; margin-bottom: 10px;'>ระบบขัดข้องทางเทคนิค (Database Connection Error)</h2>
        <p>ไม่สามารถเชื่อมต่อฐานข้อมูลได้ กรุณาตรวจสอบสถานะและพารามิเตอร์การเชื่อมต่อ</p>
        <hr style='border: 0; border-top: 1px solid #BD2130; margin: 15px 0;'>
        <small style='color: #666;'>ความเสียหายของโครงสร้าง: ปฏิเสธการเชื่อมต่อจากฐานข้อมูลหลัก</small>
        {$error_details}
    </div>");
}

/**
 * Send External Notification (LINE Notify / Webhook Log) for Payment Submissions
 */
if (!function_exists('send_payment_notification')) {
    function send_payment_notification($store_name, $plan_name, $amount) {
        $line_token = getenv('LINE_NOTIFY_TOKEN') ?: '';
        $message = "\n🔔 มีการชำระเงินใหม่!\nร้าน: {$store_name}\nแพ็กเกจ: {$plan_name}\nจำนวน: " . number_format($amount, 2) . " บาท\nกรุณาเข้าตรวจสอบในระบบ Super Admin";

        if (!empty($line_token)) {
            @$ch = curl_init('https://notify-api.line.me/api/notify');
            if ($ch) {
                curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer {$line_token}"]);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['message' => $message]));
                curl_setopt($ch, CURLOPT_TIMEOUT, 5);
                curl_exec($ch);
                curl_close($ch);
            }
        }

        $log_entry = date('Y-m-d H:i:s') . " | PAYMENT_ALERT | Store: {$store_name} | Plan: {$plan_name} | Amount: {$amount} THB\n";
        @file_put_contents(__DIR__ . '/payment_notifications.log', $log_entry, FILE_APPEND);
    }
}

/**
 * CSRF Protection Helper Functions
 */
if (!function_exists('generate_csrf_token')) {
    function generate_csrf_token() {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }
}

if (!function_exists('verify_csrf_token')) {
    function verify_csrf_token($token) {
        if (empty($_SESSION['csrf_token']) || empty($token)) {
            return false;
        }
        return hash_equals($_SESSION['csrf_token'], $token);
    }
}

/**
 * XSS Sanitation Helper
 */
if (!function_exists('e')) {
    function e($string) {
        return htmlspecialchars($string ?? '', ENT_QUOTES, 'UTF-8');
    }
}

/**
 * High-Performance Image Resizing and Compression Utility using PHP GD Library
 * 
 * - Resizes images exceeding 1200px width down to 1200px maintaining original aspect ratio.
 * - Preserves transparency/alpha channel for PNG, WebP, GIF formats.
 * - Compresses JPEG/WEBP to 80% quality keeping file sizes between 300KB-800KB.
 * - Cleans up GD memory resources via imagedestroy().
 * - Gracefully falls back to move_uploaded_file() or copy() if GD is unavailable or encounters unsupported mime types.
 *
 * @param string $source_path      Uploaded temporary or source image path
 * @param string $dest_path        Target save path for optimized image
 * @param int    $max_width        Maximum width allowed in pixels (default 1200)
 * @param int    $quality          Compression quality percentage (default 80)
 * @return bool                    True on success, false on error
 */
if (!function_exists('processAndCompressImage')) {
    function processAndCompressImage($source_path, $dest_path, $max_width = 1200, $quality = 80) {
        if (!file_exists($source_path) || !is_readable($source_path)) {
            return false;
        }

        // Ensure destination folder exists and is writable
        $dest_dir = dirname($dest_path);
        if (!is_dir($dest_dir)) {
            @mkdir($dest_dir, 0777, true);
        }

        // Fallback if GD library extension is not loaded
        if (!extension_loaded('gd') || !function_exists('imagecreatetruecolor')) {
            if (is_uploaded_file($source_path)) {
                return @move_uploaded_file($source_path, $dest_path);
            }
            return @copy($source_path, $dest_path);
        }

        $info = @getimagesize($source_path);
        if (!$info) {
            if (is_uploaded_file($source_path)) {
                return @move_uploaded_file($source_path, $dest_path);
            }
            return @copy($source_path, $dest_path);
        }

        $mime = $info['mime'] ?? '';
        $orig_width = $info[0] ?? 0;
        $orig_height = $info[1] ?? 0;

        if ($orig_width <= 0 || $orig_height <= 0) {
            if (is_uploaded_file($source_path)) {
                return @move_uploaded_file($source_path, $dest_path);
            }
            return @copy($source_path, $dest_path);
        }

        // Create GD resource based on original image mime type
        $src_img = null;
        switch ($mime) {
            case 'image/jpeg':
            case 'image/pjpeg':
                $src_img = @imagecreatefromjpeg($source_path);
                break;
            case 'image/png':
                $src_img = @imagecreatefrompng($source_path);
                break;
            case 'image/webp':
                $src_img = function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($source_path) : null;
                break;
            case 'image/gif':
                $src_img = @imagecreatefromgif($source_path);
                break;
            case 'image/bmp':
            case 'image/x-ms-bmp':
                $src_img = function_exists('imagecreatefrombmp') ? @imagecreatefrombmp($source_path) : null;
                break;
        }

        // Fallback if image GD creation fails
        if (!$src_img) {
            if (is_uploaded_file($source_path)) {
                return @move_uploaded_file($source_path, $dest_path);
            }
            return @copy($source_path, $dest_path);
        }

        // Calculate aspect ratio preserving dimensions
        if ($orig_width > $max_width) {
            $new_width = $max_width;
            $new_height = (int)round($orig_height * ($max_width / $orig_width));
        } else {
            $new_width = $orig_width;
            $new_height = $orig_height;
        }

        // Create new image canvas
        $dst_img = @imagecreatetruecolor($new_width, $new_height);
        if (!$dst_img) {
            @imagedestroy($src_img);
            if (is_uploaded_file($source_path)) {
                return @move_uploaded_file($source_path, $dest_path);
            }
            return @copy($source_path, $dest_path);
        }

        // Preserve transparency / alpha channel for PNG, WebP, GIF
        if ($mime === 'image/png' || $mime === 'image/webp' || $mime === 'image/gif') {
            @imagealphablending($dst_img, false);
            @imagesavealpha($dst_img, true);
            $transparent = @imagecolorallocatealpha($dst_img, 255, 255, 255, 127);
            @imagefilledrectangle($dst_img, 0, 0, $new_width, $new_height, $transparent);
        }

        // Resample original image onto newly dimensioned canvas
        @imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $new_width, $new_height, $orig_width, $orig_height);

        // Save image file according to target extension
        $dest_ext = strtolower(pathinfo($dest_path, PATHINFO_EXTENSION));
        $saved = false;

        if ($dest_ext === 'png') {
            $png_quality = (int)round((100 - $quality) / 10);
            if ($png_quality < 0) $png_quality = 0;
            if ($png_quality > 9) $png_quality = 9;
            $saved = @imagepng($dst_img, $dest_path, $png_quality);
        } elseif ($dest_ext === 'webp' && function_exists('imagewebp')) {
            $saved = @imagewebp($dst_img, $dest_path, $quality);
        } else {
            $saved = @imagejpeg($dst_img, $dest_path, $quality);
        }

        // Clean up temporary GD memory resources
        @imagedestroy($src_img);
        @imagedestroy($dst_img);

        // Fallback if saving failed
        if (!$saved || !file_exists($dest_path)) {
            if (is_uploaded_file($source_path)) {
                return @move_uploaded_file($source_path, $dest_path);
            }
            return @copy($source_path, $dest_path);
        }

        return true;
    }
}
?>
