<?php

if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Checked if not exists WINGS3DPR_Shortcodes class.
 */
if ( !class_exists( 'WINGS3DPR_Shortcodes' ) ) {
    /**
     * WINGS3DPR_Shortcodes class file.
     */
    class WINGS3DPR_Shortcodes {
        public static bool $shortcode_used = false;

        /**
         * WINGS3DPR_Shortcodes class constructor.
         */
        public function __construct() {
            add_shortcode( '3d_model_interactive', array($this, 'render_shortcode') );
            add_action( 'wp_enqueue_scripts', array($this, 'enqueue_scripts') );
            add_filter( 'manage_wings3dpr_model_posts_columns', array($this, 'add_custom_columns') );
            add_action(
                'manage_wings3dpr_model_posts_custom_column',
                array($this, 'populate_custom_columns'),
                10,
                2
            );
            add_filter(
                'script_loader_tag',
                array($this, 'add_type_module_attribute'),
                10,
                2
            );
        }

        /**
         * Add 'type="module"' attribute to a script tag.
         *
         * @param string $tag    The HTML tag for the script.
         * @param string $handle The handle of the script being processed.
         * @return string Modified HTML tag with the module type attribute if applicable.
         */
        public function add_type_module_attribute( $tag, $handle ) {
            if ( 'model-viewer-min' === $handle || 'model-viewer-effects-min' === $handle || 'tpv-three-module-min' === $handle ) {
                return str_replace( 'src', 'type="module" src', $tag );
            }
            return $tag;
        }

        /**
         * Add custom columns to the post list table for the model post type.
         *
         * @param array $columns An array of existing column names and titles.
         * @return array Modified array of columns with the new custom column added.
         */
        public function add_custom_columns( $columns ) {
            $new_columns = array(
                'model_preview' => __( '3D Model Interactive Shortcode', 'wingstech-3d-product-viewer-interactive' ),
            );
            return array_slice(
                $columns,
                0,
                -1,
                true
            ) + $new_columns + array_slice(
                $columns,
                -1,
                1,
                true
            );
        }

        /**
         * Display custom column shortcode in the post list table.
         *
         * @param string $column The name of the column to populate.
         * @param int    $post_id The ID of the post.
         */
        public function populate_custom_columns( $column, $post_id ) {
            if ( 'model_preview' === $column ) {
                ?>
			<div class="shortcode-wrapper">
				<code id="shortcode-<?php 
                echo esc_attr( $post_id );
                ?>">[3d_model_interactive id="<?php 
                echo esc_attr( $post_id );
                ?>"]</code>
				<button class="copy-button" data-id="<?php 
                echo esc_attr( $post_id );
                ?>">
					<?php 
                esc_html_e( 'Copy', 'wingstech-3d-product-viewer-interactive' );
                ?>
				</button>
				<span class="tooltip" id="tooltip-<?php 
                echo esc_attr( $post_id );
                ?>">
					<?php 
                esc_html_e( 'Copied!', 'wingstech-3d-product-viewer-interactive' );
                ?>
				</span>
			</div>
			<?php 
            }
        }

        /**
         * Include JS and CSS for frontend.
         */
        public function enqueue_scripts() {
            $post = get_post();
            $has_shortcode = $post instanceof \WP_Post && has_shortcode( $post->post_content, '3d_model_interactive' );
            if ( $has_shortcode || self::$shortcode_used ) {
                wp_enqueue_style(
                    'model-public',
                    WINGS3DPR_PLUGIN_URL . 'inc/assets/css/model-public.css',
                    array(),
                    WINGS3DPR_PLUGIN_VER
                );
                $threeModule = WINGS3DPR_PLUGIN_URL . 'inc/assets/js/three.module.min.js';
                $import_map = [
                    'imports' => [
                        'three' => $threeModule,
                    ],
                ];
                ?>
				<script type="importmap">
					<?php 
                echo wp_json_encode( $import_map, JSON_UNESCAPED_SLASHES );
                ?>
				</script>
				<?php 
                wp_enqueue_script(
                    'model-viewer-min',
                    WINGS3DPR_PLUGIN_URL . 'inc/assets/js/model-viewer.min.js',
                    null,
                    WINGS3DPR_PLUGIN_VER,
                    true
                );
                wp_enqueue_script(
                    'model-viewer-effects-min',
                    WINGS3DPR_PLUGIN_URL . 'inc/assets/js/model-viewer-effects.min.js',
                    array('jquery'),
                    WINGS3DPR_PLUGIN_VER,
                    true
                );
                wp_enqueue_script(
                    'qrcode',
                    WINGS3DPR_PLUGIN_URL . 'inc/assets/js/qrcode.js',
                    null,
                    WINGS3DPR_PLUGIN_VER,
                    true
                );
                wp_enqueue_script(
                    'model-public',
                    WINGS3DPR_PLUGIN_URL . 'inc/assets/js/model-public.js',
                    array('jquery'),
                    WINGS3DPR_PLUGIN_VER,
                    true
                );
            }
        }

        /**
         * Render the model viewer shortcode.
         *
         * @param array $atts Shortcode attributes.
         * @return string The HTML output for the model viewer or an empty string if no valid ID is provided.
         */
        public function render_shortcode( $atts ) {
            self::$shortcode_used = true;
            $atts = shortcode_atts( array(
                'id'              => '',
                'width'           => '1000px',
                'height'          => '100px',
                'shadow'          => '1',
                'auto_rotate'     => 'true',
                'camera_controls' => 'true',
            ), $atts, '3d_model_interactive' );
            if ( !empty( $atts['id'] ) ) {
                $post_id = intval( $atts['id'] );
                if ( 'publish' === get_post_status( $post_id ) ) {
                    ob_start();
                    echo wp_kses( self::tpv_3d_model_html( $post_id ), WINGS3DPR_Admin_Settings::get_allowed_html() );
                    return ob_get_clean();
                }
            }
        }

        /**
         * Generate QR code for the model.
         *
         * This method generates a QR code that links to the permalink of the specified post.
         * The QR code and related HTML are only outputted on the frontend, not in the admin area.
         *
         * @param int $model_id The ID of the model.
         * @param int $post_id The ID of the post whose permalink will be encoded in the QR code.
         * @return string HTML content for the QR code and AR button.
         */
        public static function tpv_generate_qr_code( $model_id, $post_id ) {
            if ( is_admin() ) {
                return;
            }
            // Get the current post URL.
            $post_url = get_permalink( $post_id );
            ob_start();
            ?>
			<div class="tpv-ar-btn">
				<a href="javascript:void(0)" data-id="<?php 
            echo esc_attr( $model_id );
            ?>">
					<img 
						src="<?php 
            echo esc_url( WINGS3DPR_PLUGIN_URL . 'inc/assets/images/ar-icon.svg' );
            ?>" 
						alt="<?php 
            esc_attr_e( 'AR Icon', 'wingstech-3d-product-viewer-interactive' );
            ?>" 
						class="tpv-ar-icon" 
						loading="lazy"
					/>
				</a>
			</div>
			<div class="tpv-ar-popup-container hide" id="tpv-ar-popup-<?php 
            echo esc_attr( $model_id );
            ?>">
				<div class="tpv-ar-popup">
					<div class="tpv-ar-popup-header">
						<?php 
            esc_html_e( 'Scan the QR Code', 'wingstech-3d-product-viewer-interactive' );
            ?>
						<span class="tpv-ar-close-btn" data-id="<?php 
            echo esc_attr( $model_id );
            ?>"><?php 
            esc_html_e( 'Close', 'wingstech-3d-product-viewer-interactive' );
            ?></span>
					</div>
					<div class="tpv-ar-popup-body">
						<div id="qr-code-container-<?php 
            echo esc_attr( $model_id );
            ?>"></div>
						<script type="text/javascript">
							document.addEventListener("DOMContentLoaded", function() {
								var container = document.getElementById("qr-code-container-<?php 
            echo esc_js( $model_id );
            ?>");
								if (container) {
									container.innerHTML = "";
									var qrcode = new QRCode(container, {
										text: "<?php 
            echo esc_js( $post_url );
            ?>",
										width: 128,
										height: 128
									});
								}
							});
						</script>
					</div>
				</div>
			</div>
			<?php 
            return ob_get_clean();
        }

        /**
         * Generate HTML for a 3D model viewer.
         *
         * This method generates the HTML for embedding a 3D model viewer in a post. It includes attributes
         * for various options such as auto-rotation, AR mode, camera controls, and more. The HTML also
         * incorporates any customization specified in the post meta.
         *
         * @param int $post_id The ID of the post from which to retrieve model settings and meta information.
         * @return string HTML content for the 3D model viewer.
         */
        public static function tpv_3d_model_html( $post_id ) {
            $get_meta = fn( $key ) => get_post_meta( $post_id, $key, true );
            $tpv_skybox_check = $get_meta( '_tpv_env_skybox' );
            $tpv_skybox_image_url = $get_meta( '_tpv_skybox_image_url' );
            $background_color = $get_meta( '_tpv_background_color' );
            // Collecting meta fields.
            $attributes = [
                'src'               => esc_url( $get_meta( '_tpv_file' ) ),
                'alt'               => esc_attr( "3D model Viewer", "wingstech-3d-product-viewer-interactive" ),
                'auto-rotate'       => ( $get_meta( '_tpv_auto_rotate' ) === '1' ? 'auto-rotate' : '' ),
                'ar ar-modes'       => ( $get_meta( '_tpv_ar_mode' ) === '1' ? 'webxr scene-viewer quick-look' : '' ),
                'ar ar-placement'   => ( $get_meta( '_tpv_place_on_wall' ) === '1' ? 'wall' : '' ),
                'camera-controls'   => ( $get_meta( '_tpv_moving_control' ) === '1' ? 'camera-controls' : '' ),
                'loading'           => ( $get_meta( '_tpv_loading_type' ) ?: '' ),
                'disable-zoom'      => ( $get_meta( '_tpv_zoom_disable' ) === '1' ? 'disable-zoom' : '' ),
                'environment-image' => esc_url( $get_meta( '_tpv_environment_image_url' ) ),
                'skybox-image'      => ( '1' === $get_meta( '_tpv_env_skybox' ) && !empty( $tpv_skybox_image_url ) ? esc_url( $tpv_skybox_image_url ) : '' ),
                'exposure'          => esc_attr( $get_meta( '_tpv_exposure_value' ) ),
                'shadow-intensity'  => esc_attr( $get_meta( '_tpv_shadow_intensity_value' ) ),
                'shadow-softness'   => esc_attr( $get_meta( '_tpv_shadow_softness_value' ) ),
                'tone-mapping'      => ( $get_meta( '_tpv_tone_mapping_option' ) !== 'aces' ? esc_attr( $get_meta( '_tpv_tone_mapping_option' ) ) : '' ),
                'poster'            => esc_url( $get_meta( '_tpv_poster_image_url' ) ),
            ];
            $fullscreen_button = ( $get_meta( '_tpv_fullscreen_mode' ) === '1' ? self::generate_fullscreen_button( $post_id ) : '' );
            $ar_model_popup = ( $get_meta( '_tpv_ar_mode' ) === '1' && !is_admin() ? self::tpv_generate_qr_code( $post_id, get_the_ID() ) : '' );
            $camera_attributes = self::generate_camera_attributes( $post_id );
            ob_start();
            ?>
			<div class="tpvModelViewerBlock">
				<div id="model<?php 
            echo esc_attr( $post_id );
            ?>" class="tpvModelViewerBlock aligncenter">
					<div class="tpv-wrapper tpv_model_parent">
						<model-editor>
							<div class="app">
								<div class="editor-body-root">
									<div class="mvContainer">
										<model-viewer-preview id="editing_adapter_<?php 
            echo esc_attr( $post_id );
            ?>" data-id="<?php 
            echo esc_attr( $post_id );
            ?>">
											<model-viewer id="model_viewer_<?php 
            echo esc_attr( $post_id );
            ?>" data-id="<?php 
            echo esc_attr( $post_id );
            ?>"
												<?php 
            foreach ( $attributes as $key => $value ) {
                if ( $value ) {
                    echo esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
                }
            }
            ?>
												<?php 
            echo wp_kses( $camera_attributes, WINGS3DPR_Admin_Settings::get_allowed_html() );
            ?>>
												<?php 
            if ( $background_color ) {
                ?>
													<style>
														model-viewer<?php 
                echo '#model_viewer_' . esc_attr( $post_id );
                ?> {
															background-color: <?php 
                echo esc_attr( $background_color );
                ?>;
														}
													</style>
												<?php 
            }
            ?>
												
												<?php 
            ?>
											</model-viewer>
										</model-viewer-preview>
									</div>
								</div>
							</div>
						</model-editor>
						<?php 
            echo wp_kses( $fullscreen_button, WINGS3DPR_Admin_Settings::get_allowed_html() );
            ?>
						<?php 
            if ( !is_admin() ) {
                echo wp_kses( $ar_model_popup, WINGS3DPR_Admin_Settings::get_allowed_html() );
            }
            ?>
					</div>
				</div>
			</div>
			<?php 
            return ob_get_clean();
        }

        /**
         * Generates camera attribute strings based on the post's metadata.
         *
         * This function retrieves various camera settings (like min/max orbits, zoom limits, etc.)
         * from the post metadata and assembles them into an attribute string to control the 
         * camera's behavior in the frontend.
         *
         * @param int $post_id The ID of the post from which metadata will be fetched.
         * @return string The assembled camera attributes as a string.
         */
        private static function generate_camera_attributes( $post_id ) {
            $get_meta = fn( $key ) => get_post_meta( $post_id, $key, true );
            $tpv_apply_yaw_limits_box = $get_meta( '_tpv_apply_yaw_limits_box' );
            $tpv_apply_pitch_limits_box = $get_meta( '_tpv_apply_pitch_limits_box' );
            $tpv_apply_minimum_zoom_box = $get_meta( '_tpv_apply_minimum_zoom_box' );
            $min_camera_orbit_x = $get_meta( '_tpv_min_camera_orbit_x' );
            $min_camera_orbit_y = $get_meta( '_tpv_min_camera_orbit_y' );
            $min_camera_orbit_z = $get_meta( '_tpv_min_camera_orbit_z' );
            $max_camera_orbit_x = $get_meta( '_tpv_max_camera_orbit_x' );
            $max_camera_orbit_y = $get_meta( '_tpv_max_camera_orbit_y' );
            $max_camera_orbit_z = $get_meta( '_tpv_max_camera_orbit_z' );
            $customize_limits_attr = '';
            // Handling conditions for min and max camera orbits.
            if ( '1' !== $tpv_apply_yaw_limits_box && '1' !== $tpv_apply_pitch_limits_box && '1' === $tpv_apply_minimum_zoom_box ) {
                $customize_limits_attr .= self::format_min_camera_orbit( $min_camera_orbit_x, $min_camera_orbit_y, $min_camera_orbit_z );
            } else {
                if ( '1' === $tpv_apply_yaw_limits_box || '1' === $tpv_apply_pitch_limits_box ) {
                    $customize_limits_attr .= self::format_min_camera_orbit( $min_camera_orbit_x, $min_camera_orbit_y, $min_camera_orbit_z );
                    $customize_limits_attr .= ' ' . self::format_max_camera_orbit( $max_camera_orbit_x, $max_camera_orbit_y, $max_camera_orbit_z );
                }
            }
            $min_field_of_view = ( $tpv_apply_minimum_zoom_box === '1' ? 'min-field-of-view="' . esc_attr( $get_meta( '_tpv_min_field_of_view' ) ) . '"' : '' );
            return "{$customize_limits_attr} {$min_field_of_view}";
        }

        /**
         * Formats the minimum camera orbit attribute.
         *
         * @param mixed $x X-axis value for the minimum orbit.
         * @param mixed $y Y-axis value for the minimum orbit.
         * @param mixed $z Z-axis value for the minimum orbit.
         * @return string The formatted min-camera-orbit attribute.
         */
        private static function format_min_camera_orbit( $x, $y, $z ) {
            $min_x = self::format_angle( $x );
            $min_y = self::format_angle( $y );
            $min_z = self::format_angle( $z );
            return 'min-camera-orbit="' . esc_attr( $min_x ) . ' ' . esc_attr( $min_y ) . ' ' . esc_attr( $min_z ) . '"';
        }

        /**
         * Formats the maximum camera orbit attribute.
         *
         * @param mixed $x X-axis value for the maximum orbit.
         * @param mixed $y Y-axis value for the maximum orbit.
         * @param mixed $z Z-axis value for the maximum orbit.
         * @return string The formatted max-camera-orbit attribute.
         */
        private static function format_max_camera_orbit( $x, $y, $z ) {
            $max_x = self::format_angle( $x );
            $max_y = self::format_angle( $y );
            $max_z = self::format_angle( $z );
            return 'max-camera-orbit="' . esc_attr( $max_x ) . ' ' . esc_attr( $max_y ) . ' ' . esc_attr( $max_z ) . '"';
        }

        /**
         * Formats an angle value with "deg" suffix if numeric.
         *
         * @param mixed $angle The angle value to format.
         * @return string The formatted angle with "deg" suffix if applicable.
         */
        private static function format_angle( $angle ) {
            return ( is_numeric( $angle ) ? "{$angle}deg" : $angle );
        }

        /**
         * Generates the HTML for the fullscreen button.
         *
         * This function returns the HTML markup for a fullscreen button, which includes an SVG icon.
         * The button allows the user to open the 3D model in fullscreen mode.
         *
         * @param int $post_id The ID of the post to which the button belongs.
         * @return string The HTML for the fullscreen button.
         */
        private static function generate_fullscreen_button( $post_id ) {
            ob_start();
            ?>
			<div class="tpv-fullscreen">
				<div id="tpvOpenBtn-<?php 
            echo esc_attr( $post_id );
            ?>" class="tpv-open-icon">
					<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
						<path fill="none" stroke="white" stroke-linecap="round" 
							stroke-linejoin="round" stroke-width="2" 
							d="m21 21l-6-6m6 6v-4.8m0 4.8h-4.8M3 16.2V21m0 0h4.8M3 21l6-6m12-7.2V3m0 0h-4.8M21 3l-6 6M3 7.8V3m0 0h4.8M3 3l6 6"/>
					</svg>
				</div>
			</div>
			<?php 
            return ob_get_clean();
        }

    }

}