<?php
/**
 * AR Display
 * https://augmentedrealityplugins.com
**/

/************* Ensure that WordPress is loaded *******************/
// Define the path to wp-load.php
$wp_load_path = dirname(__FILE__) . '/../../../../wp-load.php';

if (file_exists($wp_load_path)) {
    require_once($wp_load_path);
} elseif (defined('ABSPATH') && file_exists(ABSPATH . 'wp-load.php')) {
    require_once(ABSPATH . 'wp-load.php');
} else {
    wp_die('WordPress core files not found.');
}
/************* Get Mime Types for corresponding files *******************/
if (!function_exists('ar_get_mime_type')){
    function ar_get_mime_type($file_path) {
        $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
        switch ($ext) {
            case 'gltf':
                return 'model/gltf+json';
            case 'glb':
                return 'model/gltf-binary';
            case 'usdz':
                return 'model/vnd.usdz+zip';
            case 'png':
                return 'image/png';
            case 'jpg':
            case 'jpeg':
                return 'image/jpeg';
            case 'webp':
                return 'image/webp';
            default:
                return 'application/octet-stream'; // Fallback MIME type
        }
    }
}

/************* Function to validate and serve the request *******************/
if (!function_exists('ar_gallery_file')){
    function ar_gallery_file($thumbnail_id, $image_url, $aspect_ratio, $orientation, $height, $width, $framed, $frame_color, $opacity) {
        global $ar_plugin_id;
        // Ensure opacity is a proper number for glTF (not a string) and clamp to [0, 1].
        $opacity = (float) $opacity;
        if ($opacity < 0) { $opacity = 0.0; }
        if ($opacity > 1) { $opacity = 1.0; }
        // Referrer Check: Ensure the request is coming from a valid source
        // Allow requests with valid nonces, from same domain, or for site's own images
        $has_valid_nonce = false;
        if (isset($_GET['_wpnonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'ar_secure_nonce')) {
            $has_valid_nonce = true;
        }
        
        $referer = isset($_SERVER['HTTP_REFERER']) ? esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : '';
        $site_host = parse_url(home_url(), PHP_URL_HOST);
        $referer_host = !empty($referer) ? parse_url($referer, PHP_URL_HOST) : '';
        
        $image_name = '';
        if ($framed =='0'){
            /*$opacity = 0;*/
            $framed = '';
        }elseif ($framed =='2'){
            $framed = '_framed';
        }else{
            $framed = '';
        }
        
        // Security check: Allow requests with valid nonce, from same domain, or for site's own files
        $is_allowed = false;
        
        // Normalize hosts for comparison (remove www prefix and handle case-insensitive)
        $site_host_normalized = preg_replace('/^www\./', '', strtolower($site_host));
        $referer_host_normalized = !empty($referer_host) ? preg_replace('/^www\./', '', strtolower($referer_host)) : '';
        
        // Priority 1: Valid nonce allows all requests
        if ($has_valid_nonce) {
            $is_allowed = true;
        }
        // Priority 2: WordPress attachment IDs are trusted
        elseif ($thumbnail_id) {
            $is_allowed = true;
        }
        // Priority 3: Check if image URL is from site's domain and in allowed directories
        elseif (!empty($image_url)) {
            $image_url_host = parse_url($image_url, PHP_URL_HOST);
            $image_url_host_normalized = !empty($image_url_host) ? preg_replace('/^www\./', '', strtolower($image_url_host)) : '';
            
            // Allow if same domain
            if (!empty($image_url_host_normalized) && $image_url_host_normalized === $site_host_normalized) {
                // Check if it's in allowed WordPress directories
                $upload_dir = wp_upload_dir();
                if (strpos($image_url, '/wp-content/uploads/') !== false || 
                    (!empty($upload_dir['baseurl']) && strpos($image_url, $upload_dir['baseurl']) !== false) ||
                    strpos($image_url, '/wp-content/plugins/') !== false ||
                    strpos($image_url, '/wp-content/themes/') !== false) {
                    $is_allowed = true;
                }
            }
        }
        
        // Priority 4: Fallback - allow if referrer is from same domain OR empty (model-viewer compatibility)
        // This is a safety net for legitimate same-domain requests when other checks might fail
        if (!$is_allowed) {
            // Allow if referrer matches OR is empty (model-viewer often doesn't send referrer)
            if (empty($referer) || (!empty($referer_host_normalized) && $referer_host_normalized === $site_host_normalized)) {
                // Additional safety: require either valid nonce OR image URL from same domain
                if ($has_valid_nonce || 
                    (!empty($image_url) && !empty($image_url_host_normalized) && $image_url_host_normalized === $site_host_normalized)) {
                    $is_allowed = true;
                }
            }
        }
        
        if (!$is_allowed) {
            status_header(403);
            wp_die('Unauthorized access');
        }
        // Get the featured image URL
        if ($thumbnail_id) {
            $image_url = wp_get_attachment_image_url($thumbnail_id, 'full'); // 'full' can be replaced with other image sizes if needed
            if (!$image_url) {
                return 'Image not found';
            }
            $image_id = $thumbnail_id;
        }elseif($image_url){
            //set aspect ratio and orientation
            $image_id = 'upload';
            $iw = (int) $width;
            $ih = (int) $height;
            // When width & height are present (user-upload style), derive ratio/orientation from
            // pixels so the GLTF frame matches the texture. Query ratio/o alone caused 1.0+square
            // meshes for non-square images (e.g. 524x480) and unstable Android WebXR.
            if ( $iw > 0 && $ih > 0 ) {
                $raw_ratio    = $iw / $ih;
                $aspect_ratio = round( $raw_ratio, 2 );
                $orientation  = 'l';
                if ( $iw < $ih ) {
                    $orientation  = 'p';
                    $aspect_ratio = round( $ih / $iw, 2 );
                } elseif ( $iw === $ih ) {
                    $orientation  = 'square';
                    $aspect_ratio = '1.0';
                }
            } else {
                // Legacy: no dimensions — use query ratio / orientation only
                if ( ! $aspect_ratio && $height !== '' && (int) $height > 0 ) {
                    $raw_ratio     = (float) $width / (float) $height;
                    $aspect_ratio  = round( $raw_ratio, 2 );
                }
                if ( ! $orientation ) {
                    $orientation = 'l';
                    if ( $width !== '' && $height !== '' && (int) $height > 0 && (float) $width < (float) $height ) {
                        $orientation = 'p';
                        $aspect_ratio = round( (float) $height / (float) $width, 2 );
                    } elseif ( $width !== '' && $height !== '' && (float) $width === (float) $height ) {
                        $orientation = 'square';
                    }
                } else {
                    $orientation = substr( $orientation, 0, 1 );
                    if ( $orientation === 'p' && $width !== '' && $height !== '' && (int) $height > 0 && (float) $width < (float) $height ) {
                        $aspect_ratio = round( (float) $height / (float) $width, 2 );
                    }
                }
            }
            // Path to the JSON file (read from filesystem to avoid loopback HTTP issues)
            $json_file_fs = plugin_dir_path( __FILE__ ) . '../assets/models/models.json';
            if ( ! file_exists( $json_file_fs ) ) {
                die('Error reading JSON file');
            }
            $json_data = file_get_contents( $json_file_fs );
            
            // Decode JSON data into a PHP array
            $data_array = json_decode($json_data, true);
            
            // Check if json_decode succeeded
            if (json_last_error() !== JSON_ERROR_NONE) {
               die( esc_html( 'Error decoding JSON data: ' . json_last_error_msg() ) );
            }
            
            if ($data_array === null) {
                die('Error decoding JSON data');
            }
            
            // Filter data array by enabled ratios and sizes from settings
            $data_array = ar_filter_gallery_data_by_settings($data_array);
            
            $aspect_ratio = (string) $aspect_ratio;
            // Check if the ratio exists in the data array
            if (!isset($data_array[$aspect_ratio])) {
                // Get the available ratios from the data array
                $available_ratios = array_keys($data_array);
                // If we have pixel dimensions and the image isn't square, avoid snapping to 1.0 (square),
                // which can create a square frame for near-square landscape/portrait images and cause
                // Android AR viewers to fail or behave unpredictably.
                if ( isset( $iw, $ih ) && $iw > 0 && $ih > 0 && $iw !== $ih ) {
                    $available_ratios = array_values(
                        array_filter(
                            $available_ratios,
                            static function ( $r ) {
                                return (string) $r !== '1.0';
                            }
                        )
                    );
                }
                // Find the closest ratio
                $aspect_ratio = ar_findClosestRatio($aspect_ratio, $available_ratios);
            }
            // Remove query string if present
            $image_name = strtok($image_url, '?');
            
            // Extract file name without the extension
            $file_info = pathinfo($image_name);
            $image_name = $file_info['filename'];
        }
        $mime_type = ar_get_mime_type($image_url);
        
        if($aspect_ratio =='1.0'){
            $orientation = 'square';
        }elseif ($orientation == 'l'){
            $orientation = 'landscape';
        }else{
            $orientation = 'portrait';
        }
        
        $upload_dir = wp_upload_dir();
        $models_dir_url = $upload_dir['baseurl'] . '/' . $ar_plugin_id . '/models/';
        $models_dir = $upload_dir['basedir'] . '/' . $ar_plugin_id . '/models/';
        $json_file_path = $models_dir . $aspect_ratio . '_' . $orientation . $framed . '.gltf';
        
        // Check if the file exists
        if (!file_exists($json_file_path)) {
        
            // Check if the folder exists, if not create it
            if (!is_dir($models_dir)) {
                wp_mkdir_p($models_dir); // Create the directory recursively
            }
        
            // Source directory within the plugin
            $source_dir = plugin_dir_path( __FILE__ ) . '../assets/models/';
        
            // Check if the source directory exists
            if (is_dir($source_dir)) {
        
                // Open the source directory
                $files = scandir($source_dir);
        
                foreach ($files as $file) {
                    if ($file !== '.' && $file !== '..') {
        
                        $source_file = $source_dir . $file;
                        $destination_file = $models_dir . $file;
        
                        // If the file has a .gltfdata extension, rename it to .bin
                        if (pathinfo($file, PATHINFO_EXTENSION) == 'gltfdata') {
                            $destination_file = $models_dir . pathinfo($file, PATHINFO_FILENAME) . '.bin';
                        }
        
                        // Copy the file from the source directory to the destination directory
                        copy($source_file, $destination_file);
                    }
                }
        
                // Log the action if needed
                //error_log("Copied files from $source_dir to $models_dir");
            } else {
                // Log error if the source directory doesn't exist
                //error_log("Source directory does not exist: $source_dir");
            }
        }
        
        // Read the GLTF JSON from filesystem instead of HTTP to avoid loopback issues
        $json_file_fs = $models_dir . $aspect_ratio . '_' . $orientation . $framed . '.gltf';
        if ( ! file_exists( $json_file_fs ) ) {
            die('Error reading JSON file gltf');
        }
        $json_data = file_get_contents( $json_file_fs );
        
        // Decode JSON data into a PHP array
        $data_array = json_decode($json_data, true);
        
        // Check if json_decode succeeded
        if (json_last_error() !== JSON_ERROR_NONE) {
            die( esc_html( 'Error decoding JSON data: ' . json_last_error_msg() ) );
        }
        
        if ($data_array === null) {
            die('Error decoding JSON data');
        }
        // Update the images array
        if (isset($data_array['images']) && is_array($data_array['images'])) {
            foreach ($data_array['images'] as &$image) {
                // Assign standard URLs to the 'uri' field without escaping slashes
                $image['uri'] = $image_url;  // Ensure $image_url is a full valid URL
                $image['mimeType'] = $mime_type;
            }
        }
        
        // Update the buffers array
        //echo $upload_dir['baseurl'];
        if (isset($data_array['buffers']) && is_array($data_array['buffers'])) {
            foreach ($data_array['buffers'] as $index => &$buffer) {
                if ($index === 0) {
                    // Use site_url() to generate the full URL to the resource
                    $site_url = str_replace('http://', 'https://', $upload_dir['baseurl']);
                    $buffer['uri'] = esc_url($site_url . '/' . $ar_plugin_id . '/models/' . $aspect_ratio . '_' . $orientation . $framed . '.bin');
                } 
            }
        }

        // Convert hex color to RGB
        function hexToRgb($hex) {
            // Remove '#' if it exists
            $hex = ltrim($hex, '#');
        
            // Ensure the hex code is valid (6 characters)
            if (strlen($hex) !== 6) {
                return [0, 0, 0]; // Return black for invalid hex
            }
            
            // Split the hex into RGB components
            $r = hexdec(substr($hex, 0, 2)) / 255;
            $g = hexdec(substr($hex, 2, 2)) / 255;
            $b = hexdec(substr($hex, 4, 2)) / 255;
        
            return [$r, $g, $b, 0];
        }
        
        $rgb = hexToRgb('#'.$frame_color);
        
        // Traverse through the data array to modify the materials
        foreach ($data_array['materials'] as &$material) {
            // Ensure "alphaMode" is set to "BLEND" for all materials
            $material['alphaMode'] = 'BLEND';
        
            // Check if the material is not named "Material.001"
            if ($material['name'] !== 'Material.001') {
                if (isset($material['pbrMetallicRoughness']['baseColorFactor'])) {
                    // Update the baseColorFactor with RGB values and opacity
                    $material['pbrMetallicRoughness']['baseColorFactor'][0] = $rgb[0]; // Red
                    $material['pbrMetallicRoughness']['baseColorFactor'][1] = $rgb[1]; // Green
                    $material['pbrMetallicRoughness']['baseColorFactor'][2] = $rgb[2]; // Blue
                    $material['pbrMetallicRoughness']['baseColorFactor'][3] = $opacity; // Opacity
                }
            }
        }
        
        
        
        // Convert the updated array to JSON
        $updated_json = wp_json_encode($data_array, JSON_UNESCAPED_SLASHES);
        
        // Prevent caching
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache'); // For HTTP/1.0 compatibility
        header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
        
        // Body is glTF JSON ($mime_type is only for images[] inside the asset).
        header('Content-Type: model/gltf+json');
        header('Content-Length: ' . strlen($updated_json));
        header('Content-Disposition: inline; filename="' . esc_attr($thumbnail_id) . $image_name . '_ar_model.gltf"');
        
        echo $updated_json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON from wp_json_encode.
        exit;
        
    }
}
// Verify the nonce before processing

if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'ar_secure_nonce' ) ) {
    wp_die( esc_html__( 'Security check failed.', 'ar-for-wordpress' ) );
}
// Get the encrypted file path from the query string
$thumbnail_id = isset($_GET['id']) ? sanitize_text_field( wp_unslash( $_GET['id'] ) ) : '';
$aspect_ratio = isset($_GET['ratio']) ? sanitize_text_field(wp_unslash($_GET['ratio'])) : '';
$orientation = isset($_GET['o']) ? sanitize_text_field(wp_unslash($_GET['o'])) : '';
$url = isset($_GET['url']) ? sanitize_text_field(wp_unslash($_GET['url'])) : '';
$height = isset($_GET['height']) ? sanitize_text_field(wp_unslash($_GET['height'])) : '';
$width = isset($_GET['width']) ? sanitize_text_field(wp_unslash($_GET['width'])) : '';
$framed = isset($_GET['f']) ? sanitize_text_field(wp_unslash($_GET['f'])) : '';
$frame_color = isset($_GET['fc']) ? sanitize_text_field(wp_unslash($_GET['fc'])) : '000000';
$opacity = isset($_GET['opacity']) ? sanitize_text_field(wp_unslash($_GET['opacity'])) : '1';

// Check if the URL is a blob URL (which can't be processed by the server)
if (strpos($url, 'blob:') === 0) {
    wp_die('Blob URLs cannot be processed by the server. Please use the proper file upload mechanism.');
}

// Validate and serve the file
ar_gallery_file($thumbnail_id, $url, $aspect_ratio, $orientation, $height, $width, $framed, $frame_color, $opacity);