<?php

namespace SmartSyncS3\Helpers;
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
use Aws\S3\S3Client;
use Exception;
use FilesystemIterator;
use InvalidArgumentException;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

/**
 * Helper class for various utility functions related to S3, file handling, and plugin compatibility.
 *
 * This class contains methods for getting region-specific pricing, checking plugin compatibility,
 * fetching file extensions, retrieving files from Amazon S3, and local directories, and formatting
 * file sizes into readable formats. It is designed to streamline operations in a SmartSyncS3 environment.
 *
 * @package SmartSyncS3
 * @author Infinitie Technologies
 *
 */

class SMARL_Helper
{

    /**
     * Returns the S3 pricing per region.
     *
     * @return array An associative array of AWS regions and their respective S3 prices.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     */
    public static function getRegionPrices(): array
    {
        return [
            'us-east-1' => 0.023, // US East (N. Virginia)
            'us-east-2' => 0.023, // US East (Ohio)
            'us-west-1' => 0.026, // US West (N. California)
            'us-west-2' => 0.023, // US West (Oregon)
            'ca-central-1' => 0.025, // Canada (Central)
            'eu-north-1' => 0.024, // EU (Stockholm)
            'eu-west-1' => 0.023, // EU (Ireland)
            'eu-west-2' => 0.024, // EU (London)
            'eu-west-3' => 0.024, // EU (Paris)
            'eu-central-1' => 0.0245, // EU (Frankfurt)
            'eu-south-1' => 0.024, // EU (Milan)
            'eu-south-2' => 0.024, // EU (Spain)
            'eu-central-2' => 0.024, // EU (Zurich)
            'me-south-1' => 0.025, // Middle East (Bahrain)
            'me-central-1' => 0.025, // Middle East (UAE)
            'af-south-1' => 0.025, // Africa (Cape Town)
            'ap-south-1' => 0.025, // Asia Pacific (Mumbai)
            'ap-south-2' => 0.025, // Asia Pacific (Hyderabad)
            'ap-southeast-1' => 0.025, // Asia Pacific (Singapore)
            'ap-southeast-2' => 0.025, // Asia Pacific (Sydney)
            'ap-southeast-3' => 0.025, // Asia Pacific (Jakarta)
            'ap-southeast-4' => 0.025, // Asia Pacific (Melbourne)
            'ap-northeast-1' => 0.025, // Asia Pacific (Tokyo)
            'ap-northeast-2' => 0.025, // Asia Pacific (Seoul)
            'ap-northeast-3' => 0.025, // Asia Pacific (Osaka)
            'sa-east-1' => 0.0405, // South America (São Paulo)
            'nyc1' => 0.10, // New York City 1 (Block Storage)
            'nyc2' => 0.10, // New York City 2 (Block Storage)
            'nyc3' => 0.10, // New York City 3 (Block Storage)
            'ams3' => 0.10, // Amsterdam 3 (Block Storage)
            'sfo2' => 0.10, // San Francisco 2 (Block Storage)
            'sfo3' => 0.10, // San Francisco 3 (Block Storage)
            'sgp1' => 0.10, // Singapore 1 (Block Storage)
            'lon1' => 0.10, // London 1 (Block Storage)
            'fra1' => 0.10, // Frankfurt 1 (Block Storage)
            'tor1' => 0.10 // Toronto 1 (Block Storage)
        ];
    }


    /**
     * Checks the plugin compatibility with server configurations.
     *
     * @return array An associative array containing a boolean 'compatible' flag and an array of errors (if any).
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     *
     */
    public static function checkPluginCompatibility(): array
    {
        $compatible = true;

        $errors = [];

        if(ini_get('max_execution_time')<120)
        {

            $compatible = false;
            $errors[] = [
                "error_key" => "max_execution_time",
                "error_message" => "max_execution_time should be atleast 120 seconds in your php.ini file of your server. <b>Current limit</b>: ".ini_get('max_execution_time')
            ];
        }

        return [
            "compatible" => $compatible,
            "error" => $errors
        ];
    }


    /**
     * Returns an array of allowed file extensions based on the provided type.
     *
     * @param string $type The type of files to filter (e.g., "media" or "assets").
     * @return array An array of file extensions allowed for the given type.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     */
    public static function getExtension(string $type): array
    {
        if ($type == "media") {
            return [
                // Images
                'jpg', 'jpeg', 'png', 'gif', 'ico', 'webp', 'bmp', 'heic', 'tiff', 'svg',

                // Documents
                'pdf', 'doc', 'docx', 'ppt', 'pptx', 'pps', 'ppsx', 'odt', 'xls', 'xlsx', 'psd',

                // Audio
                'mp3', 'm4a', 'ogg', 'wav', 'aac',

                // Video
                'mp4', 'm4v', 'mov', 'wmv', 'avi', 'mpg', 'ogv', '3gp', '3g2', 'flv', 'mkv', 'webm', 'mpeg'
            ];

        } elseif ($type == "assets") {
            return ['css', 'js'];
        }
        return [];
    }

    /**
     * Function to check CNAME record for a domain
     *
     * @param string $domain The domain to check
     * @return string|null Returns the CNAME record or null if not found
     */
    public static function checkCNAME($domain)
    {
        // Use dns_get_record to fetch DNS records of type CNAME
        $records = dns_get_record($domain, DNS_CNAME);

        // Check if a CNAME record exists
        if (!empty($records) && isset($records[0]['target'])) {
            return $records[0]['target'];
        }

        return null; // No CNAME record found
    }

    /**
     * Extracts the file extension from a given URL.
     *
     * @param string $url The URL from which to extract the file extension.
     * @return string|null The file extension, or null if none is found.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     */
    public static function getFileExtensionFromUrl(string $url): string|null
    {
        $path = wp_parse_url($url, PHP_URL_PATH);

        return pathinfo($path, PATHINFO_EXTENSION);
    }

    /**
     * Retrieves a list of files from an S3 bucket.
     *
     * @param S3Client $s3Client The S3 client used to interact with the bucket.
     * @param string $bucket The name of the S3 bucket from which you want to receive files.
     * @return array An array of files with their keys and sizes.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     */
    public static function getS3Files(S3Client $s3Client, string $bucket): array
    {
        $all_files = [];
        $args = ['Bucket' => $bucket];

        do {
            $objects = $s3Client->listObjectsV2($args);

            foreach ($objects['Contents'] as $object) {
                $all_files[] = [
                    'key' => $object['Key'],
                    'size' => $object['Size']
                ];
            }

            $args['ContinuationToken'] = $objects['NextContinuationToken'];
        } while ($objects['IsTruncated']);

        return $all_files;
    }

    /**
     * Retrieves local files from a specified directory that match allowed extensions.
     *
     * @param string $uploads_dir The directory path to scan for files.
     * @param array $extensions An array of allowed file extensions.
     * @return array An array of local files, including their absolute and relative paths.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     */
    public static function updateLocalFilesDB(string $uploads_dir, array $extensions = []): array {
        // Initialize files array
        $all_files = [];

        // Helper function to recursively get files (unchanged)
        $getFiles = function ($dir) use (&$getFiles, $uploads_dir, $extensions, &$all_files) {
            // Check if the directory exists
            if (is_dir($dir)) {
                // Open the directory
                if ($handle = opendir($dir)) {
                    // Loop through the files in the directory
                    while (($file = readdir($handle)) !== false) {
                        if ($file != '.' && $file != '..') {
                            $file_path = $dir . DIRECTORY_SEPARATOR . $file;
                            if (is_dir($file_path)) {
                                $getFiles($file_path);
                            } else {
                                $file_extension = pathinfo($file_path, PATHINFO_EXTENSION);
                                if (empty($extensions) || in_array($file_extension, $extensions)) {
                                    $absolute_path = realpath($file_path);
                                    $relative_path = str_replace($uploads_dir, '', $absolute_path);
                                    $all_files[] = [
                                        'path' => $absolute_path,
                                        'relative_path' => $relative_path,
                                        'status' => 'pending'
                                    ];
                                }
                            }
                        }
                    }
                    closedir($handle);
                }
            }
        };

        // Collect files
        $getFiles($uploads_dir);

        // Store files in database through a custom method
        self::save_files_to_database($all_files);

        return $all_files;
    }

    /**
     * Save files to database with proper caching
     *
     * @param array $files Array of file data to save
     * @return void
     */
    private static function save_files_to_database(array $files): void {
        global $wpdb;

        $table_name = $wpdb->prefix . 'smarl_file_sync_queue';

        // Clear the existing table
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $wpdb->query("DELETE FROM {$wpdb->prefix}smarl_file_sync_queue");

        // Process files in chunks
        $chunk_size = 50;

        foreach (array_chunk($files, $chunk_size) as $chunk) {
            foreach ($chunk as $file) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
                $wpdb->insert(
                    $table_name,
                    array(
                        'path' => $file['path'],
                        'relative_path' => $file['relative_path'],
                        'status' => $file['status']
                    ),
                    array('%s', '%s', '%s')
                );

                // Optional: Update the cache
                wp_cache_set('file_' . md5($file['path']), $file, 'smarl_file_sync_queue');
            }
        }

        // Invalidate any existing cache for file lists
        wp_cache_delete('all_files', 'smarl_file_sync_queue');
    }

    /**
     * Fetches file sync queue data with caching.
     *
     * @param int $limit Number of records to fetch.
     * @param int $offset Offset for pagination.
     * @return array List of file sync queue records.
     */
    public static function getFileSyncQueueData(int $limit = 50, int $offset = 0): array {
        global $wpdb;

        // Properly escape table name to prevent SQL errors
        $table_name = esc_sql($wpdb->prefix . 'smarl_file_sync_queue');

        // Cache key for optimized performance
        $cache_key = "smarl_file_sync_queue_{$limit}_{$offset}";
        $cached_results = wp_cache_get($cache_key, 'smarl_file_sync_queue');

        if ($cached_results !== false) {
            return $cached_results; // Return cached results if available
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$table_name} WHERE status = %s LIMIT %d OFFSET %d",
            'pending',
            $limit,
            $offset
        ), ARRAY_A);

        // Store results in cache for 5 minutes
        if (!empty($results)) {
            wp_cache_set($cache_key, $results, 'smarl_file_sync_queue', 300);
        }

        return $results;
    }


    /**
     * Formats a byte value into a human-readable string (e.g., KB, MB, GB).
     *
     * @param int $bytes The size in bytes to format.
     * @return string The formatted size string.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     */
    public static function formatBytes(int $bytes): string
    {
        $units = ['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, 2) . ' ' . $units[$pow];
    }

    /**
     *
     * Replaces the base URL with new baseurl from the original URL.
     *
     * @param string $originalUrl Original URL to replace.
     * @param string $newBaseUrl New base url to replace in base url.
     * @developer Jay Parmar <infinitie.jay@gmail.com>
     *
     * @throws Exception
     */
    public static function replaceBaseUrl(string $originalUrl, string $newBaseUrl): string {
        try {
            // Remove trailing slash from newBaseUrl if present
            $newBaseUrl = rtrim($newBaseUrl, '/');

            // Parse the original URL into components
            $urlParts = wp_parse_url($originalUrl);
            if ($urlParts === false) {
                return $originalUrl;
            }

            // Build the path with query parameters and fragment
            $path = $urlParts['path'] ?? '';

            // Add query parameters if they exist
            if (isset($urlParts['query'])) {
                $path .= '?' . $urlParts['query'];
            }

            // Add fragment (hash) if it exists
            if (isset($urlParts['fragment'])) {
                $path .= '#' . $urlParts['fragment'];
            }

            return $newBaseUrl . $path;
        } catch (Exception) {
            return $originalUrl;
        }
    }

    public static function calculateStorageDigitalOceanPrice(int $totalBytes): float
    {
        $provider = "digitalocean";
        $baseCosts = [
            'digitalocean' => 5.00, // Base cost for 250GB and 1TB outbound data transfer
        ];

        $perGbCosts = [
            'digitalocean' => 0.02, // Cost per GB for additional storage beyond 250GB
        ];

        $includedStorage = [
            'digitalocean' => 250 * 1024 * 1024 * 1024, // 250GB included
        ];

        // Ensure provider is valid
        if (!isset($baseCosts[$provider])) {
            throw new InvalidArgumentException("Unsupported provider: ".wp_kses_post("$provider"));
        }

        // Determine additional storage cost
        $baseCost = $baseCosts[$provider];
        $perGbCost = $perGbCosts[$provider];
        $includedBytes = $includedStorage[$provider];

        $additionalCost = 0.00;
        if ($totalBytes > $includedBytes) {
            $additionalBytes = $totalBytes - $includedBytes;
            $additionalGb = $additionalBytes / (1024 * 1024 * 1024);
            $additionalCost = $additionalGb * $perGbCost;
        }

        return round(num:$baseCost + $additionalCost, precision: 4);
    }

    public static function renderSwitch($id = "toggle", $on = "on", $off = "off", $additional_attr = [], $checked = true, $onSvg = "", $offSvg = ""): void
    {
        ?>
        <div class="switch">
            <div class="icon">

                <?php echo wp_kses_post(data: $onSvg) ?>
                <?php echo wp_kses_post(data: $offSvg) ?>
            </div>
            <label for="<?php echo wp_kses_post($id) ?>" aria-label="Toggle Filter">
                <input type="checkbox" id="<?php echo wp_kses_post(data: $id) ?>"
                    <?php
                    foreach ($additional_attr as $key => $value) {
                        echo wp_kses_post($key) . '="' . wp_kses_post(htmlspecialchars($value, ENT_QUOTES, 'UTF-8')) . '" ';
                    }
                    if ($checked) {
                        echo 'checked';
                    }
                    ?>
                       data-on="<?php echo wp_kses_post(htmlspecialchars($on, ENT_QUOTES, 'UTF-8')) ?>"
                       data-off="<?php echo wp_kses_post(htmlspecialchars($off, ENT_QUOTES, 'UTF-8')) ?>">
            </label>

            <span class="led">

            </span>
        </div>
        <?php

    }

    public static function renderProModal(): string{

        // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- not in media library.
        $url =' <img src="'. plugin_dir_url(__FILE__) . 'images/upgrade.png'.'" alt="Upgrade" style="width: 100%; max-width: 300px; display: block; margin: 0 auto;">';
         return '<div id="bmp-modal" class="bmp-modal">
                    <div class="bmp-modal-content">
                        <span class="bmp-close">&times;</span>
                        <div class="bmp-modal-body">
                            <p>This feature is not available in the free version. Please buy the full version to access this feature.</p>
                           '.$url.'
                            <p style="text-align: center;"><a target="_blank" href="https://example.com/buy" class="button button-primary">Buy Full Version</a></p>
                        </div>
                    </div>
                </div>';
    }
}
// TODO: Add url