<?php

/**
 * The file that defines the core plugin configurator class
 *
 * @link       https://wpconfiguratorbuilder.com
 * @since      1.0.0
 *
 * @package    wcb-configurator-builder
 * @subpackage wcb-configurator-builder/includes
 */

if ( ! defined('ABSPATH') ) {
	die();
}

use Carbon_Fields\Container;
use Carbon_Fields\Field;

/**
 * The core plugin configurator class.
 *
 * This is used to define core configurator post type and maintain its data.
 *
 * @since      1.0.0
 * @package    wcb-configurator-builder
 * @subpackage wcb-configurator-builder/includes
 * @author     WPCB <support@wpconfiguratorbuilder.com>
 */

class WPCB_Visual
{
	/**
	 * Initialize the class and set its properties.
	 *
	 * @since    1.0.0
	 * @param    string $plugin_name       The name of this plugin.
	 * @param    string $version   		   The version of this plugin.
	 */
	public function __construct()
	{
		add_action( 'init', array($this, 'register_visual') );
		add_action( 'carbon_fields_register_fields', array( $this, 'register_visual_fields' ) );
		// add_action( 'save_post_wpcb_visual', array( $this, 'clear_transients' ) );

		add_action( 'wp_ajax_wpcb_get_configuration_visuals', array( $this, 'ajax_get_configuration_visuals' ) );
		add_action( 'wp_ajax_nopriv_wpcb_get_configuration_visuals', array( $this, 'ajax_get_configuration_visuals' ) );

		add_filter( 'manage_wpcb_visual_posts_columns', array( $this, 'set_visual_columns' ) );
		add_action( 'manage_wpcb_visual_posts_custom_column', array( $this, 'fill_visual_columns' ), 10, 2 );
	}

	/**
	 * Registers the configurator for the admin area.
	 *
	 * @since    1.0.0
	 */
	public function register_visual()
	{
		$labels = array(
			'name'               => __('Visuals', 'wcb-configurator-builder'),
			'singular_name'      => __('Visual', 'wcb-configurator-builder'),
			'menu_name'          => __('Visuals', 'wcb-configurator-builder'),
			'name_admin_bar'     => __('Visual', 'wcb-configurator-builder'),
			'add_new'            => __('New visual', 'wcb-configurator-builder'),
			'add_new_item'       => __('Add new visual', 'wcb-configurator-builder'),
			'new_item'           => __('New visual', 'wcb-configurator-builder'),
			'edit_item'          => __('Edit visual', 'wcb-configurator-builder'),
			'view_item'          => __('View visual', 'wcb-configurator-builder'),
			'all_items'          => __('Visuals', 'wcb-configurator-builder'),
			'search_items'       => __('Search visuals', 'wcb-configurator-builder'),
			'parent_item_colon'  => __('Parent visuals:', 'wcb-configurator-builder'),
			'not_found'          => __('No visual found.', 'wcb-configurator-builder'),
			'not_found_in_trash' => __('No visual found in bin.', 'wcb-configurator-builder'),
		);

		$args = array(
			'labels'             => $labels,
			'public'             => false,
			'publicly_queryable' => false,
			'show_ui'            => true,
			'show_in_menu'       => 'edit.php?post_type=wpcb_configuration',
			'query_var'          => false,
			'rewrite'            => false,
			'with_front'         => false,
			'capability_type'    => 'post',
			'has_archive'        => false,
			'hierarchical'       => false,
			'supports'           => array('title'),
		);

		register_post_type('wpcb_visual', $args);
	}

	/**
	 * Set configurator columns in admin list view.
	 *
	 * @since    1.0.0
	 */
	public function set_visual_columns($columns)
	{
		unset($columns['title']);
		unset($columns['date']);

		$new_columns = array(
			'title'    => __('Visual', 'wcb-configurator-builder'),
			'configuration' => __('Configuration', 'wcb-configurator-builder'),
			'product'  => __('Product', 'wcb-configurator-builder'),
			'date'     => __('Date', 'wcb-configurator-builder'),
		);

		$columns = array_merge($columns, $new_columns);

		return $columns;
	}

	/**
	 * Fills the configurator list view column values.
	 *
	 * @since    1.0.0
	 */
	public function fill_visual_columns($column, $post_id)
	{
		if ('configuration' === $column) {
			if ( $conf_ids = carbon_get_post_meta( $post_id, 'configuration' ) ) {
				$links = [];
				foreach ( $conf_ids as $conf_id ) {
					if ( $conf_id ) {
						$links[] = '<a href="' . esc_url( admin_url( 'post.php?post=' ) ) . esc_attr( $conf_id ) . '&action=edit" target="_blank">' . esc_attr( get_the_title( $conf_id ) ) . '</a>';
					}
				}
				if ( count( $links ) > 0 ){
					echo wp_kses_post( implode( ', ', $links ) );
				} else {
					echo '-';
				}
			} else {
				echo '-';
			}
		} else if ('product' === $column) {
			if ( $product_ids = carbon_get_post_meta( $post_id, 'product' ) ) {
				$links = [];
				foreach ( $product_ids as $product_id ) {
					if ( $product_id ) {
						$links[] = '<a href="' . esc_url( admin_url( 'post.php?post=' ) ) . esc_attr( $product_id ) . '&action=edit" target="_blank">' . esc_attr( get_the_title( $product_id ) ) . '</a>';
					}
				}
				if ( count( $links ) > 0 ){
					echo wp_kses_post( implode( ', ', $links ) );
				} else {
					echo '-';
				}
			} else {
				echo '-';
			}
		}
	}

	/**
	 * Registers the Carbon Fields for our configurator post type.
	 *
	 * @since    1.0.0
	 */
	public function register_visual_fields() {

		$visual_item_fields = array();

		$post_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : false;
		if ( ! $post_id && isset( $_POST['post_ID'] ) ) {
			$post_id = absint( $_POST['post_ID'] );
		}

		if ( 'model' === wpcb_get_option( 'wpcb_configuration_visual_type' ) || 'model' === get_post_meta( $post_id, '_visual_type', true ) ) {

			array_push( $visual_item_fields,
				Field::make( 'select', 'type', __( 'Visual type', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_options( array(
						'variant' => __( 'Variant', 'wcb-configurator-builder' ),
						'model' => __( '3D model', 'wcb-configurator-builder' ),
						'material' => __( 'Material', 'wcb-configurator-builder' ),
						'node' => __( 'Node', 'wcb-configurator-builder' ),
						'hotspot' => __( 'Hotspot', 'wcb-configurator-builder' ),
						'animation' => __( 'Animation', 'wcb-configurator-builder' ),
					) ),
				Field::make( 'text', 'name', __( 'Material name', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_conditional_logic( array( array(
						'field' => 'type',
						'value' => 'material'
					))),
				Field::make( 'select', 'texture_type', __( 'Material type', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_options( array(
						'base' => __( 'Base Texture', 'wcb-configurator-builder' ),
						'color' => __( 'Base Color', 'wcb-configurator-builder' ),
						'metallic' => __( 'Metallic Texture', 'wcb-configurator-builder' ),
						'normal' => __( 'Normal Texture', 'wcb-configurator-builder' ),
						'occlusion' => __( 'Occlusion Texture', 'wcb-configurator-builder' ),
						'emissive' => __( 'Emissive Texture', 'wcb-configurator-builder' ),
						'metalness' => __( 'Metalness Factor', 'wcb-configurator-builder' ),
						'roughness' => __( 'Roughness Factor', 'wcb-configurator-builder' ),
					) )
					->set_conditional_logic( array( array(
						'field' => 'type',
						'value' => 'material'
					))),
				Field::make( 'image', 'texture', __( 'Texture', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_conditional_logic( array( array(
						'field' => 'type',
						'value' => 'material'
					), array(
						'field' => 'texture_type',
						'value' => array( 'color', 'metalness', 'roughness' ),
						'compare' => 'NOT IN'
					))),
				Field::make( 'file', 'model_file', __( '3D model', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_conditional_logic( array( array(
						'field' => 'type',
						'value' => 'model'
					))),
				Field::make( 'text', 'model_value', __( 'Visual value', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_conditional_logic( array(
						'relation' => 'OR',
						array(
							'field' => 'type',
							'value' => array( 'model', 'variant', 'node', 'hotspot', 'animation' ),
							'compare' => 'IN'
						), array(
							'field' => 'texture_type',
							'value' => array( 'metalness', 'roughness' ),
							'compare' => 'IN'
						)
					)),
				Field::make( 'select', 'animation_type', __( 'Animation type', 'wcb-configurator-builder' ) )
					->set_width( 25 )
					->set_options( array(
						'once' => __( 'Play once', 'wcb-configurator-builder' ),
						'loop' => __( 'Infinite loop', 'wcb-configurator-builder' ),
					) )
					->set_conditional_logic( array( array(
						'field' => 'type',
						'value' => 'animation'
					))),
			);
		} else {
			array_push( $visual_item_fields,
				Field::make( 'media_gallery', 'image', __( 'Visuals', 'wcb-configurator-builder' ) )
					->set_help_text( __( 'Add your base visual images here', 'wcb-configurator-builder' ) )
					->set_duplicates_allowed( false )
					->set_type( array( 'image' ) )
					->set_width( 60 ),
				Field::make( 'text', 'layer', __( 'Layers', 'wcb-configurator-builder' ) )
					->set_help_text( __( 'Higher numbers will show on top. Enter multiple values comma separated.', 'wcb-configurator-builder' ) )
					->set_width( 20 ),
				Field::make( 'text', 'index', __( 'Indexes', 'wcb-configurator-builder' ) )
					->set_help_text( __( 'Index the visual appears on. Enter multiple values comma separated.', 'wcb-configurator-builder' ) )
					->set_width( 20 ),
			);
		}

		array_push( $visual_item_fields,
			Field::make( 'complex', 'rules', __( 'Display rules', 'wcb-configurator-builder' ) )
				->setup_labels( array(
					'plural_name' => __( 'Rules', 'wcb-configurator-builder' ),
					'singular_name' => __( 'Rule', 'wcb-configurator-builder' ),
				) )
				->set_classes( 'cf-complex-rules' )
				->add_fields( array(
					Field::make( 'select', 'choice', __( 'Choice field', 'wcb-configurator-builder' ) )
						->set_width( 50 )
						->set_classes( 'wpcb-rule-choice' )
						->add_options( 'wpcb_get_configurator_choices' ),
					Field::make( 'select', 'option', __( 'Value(s)', 'wcb-configurator-builder' ) )
						->set_width( 50 )
						->set_classes( 'wpcb-rule-choice-option' )
						->add_options( 'wpcb_get_configurator_choice_options' ),
				) ),
		);

		Container::make( 'post_meta', __( 'Configuration visuals', 'wcb-configurator-builder' ) )
			->where( 'post_type', '=', 'wpcb_visual' )
			->add_fields( array(
				Field::make( 'multiselect', 'configuration', __( 'Configuration', 'wcb-configurator-builder' ) )
					->set_width( 50 )
					->add_options( 'wpcb_get_configurations' ),
				Field::make( 'multiselect', 'product', __( 'Product', 'wcb-configurator-builder' ) )
					->set_width( 50 )
					->add_options( 'wpcb_get_product_list' ),
				Field::make( 'select', 'visual_dimensions', __( 'Visual dimensions', 'wcb-configurator-builder' ) )
					->set_width( 50 )
					->set_help_text( __( 'Select whether this visual group contains dimension layers or not', 'wcb-configurator-builder' ) )
					->add_options( array(
						'no' => __( 'No', 'wcb-configurator-builder' ),
						'yes' => __( 'Yes', 'wcb-configurator-builder' ),
					) ),
				Field::make( 'select', 'visual_type', __( 'Visual type', 'wcb-configurator-builder' ) )
					->set_width( 50 )
					->set_help_text( __( 'This change requires an update', 'wcb-configurator-builder' ) )
					->add_options( array(
						'inherit' => __( 'Inherit from settings', 'wcb-configurator-builder' ),
						'image' => __( '2D image', 'wcb-configurator-builder' ),
						'model' => __( '3D model', 'wcb-configurator-builder' ),
					) ),
				Field::make( 'complex', 'visuals', __( 'Visuals', 'wcb-configurator-builder' ) )
					->set_datastore( new WPCB_Datastore() )
					->setup_labels( array(
						'plural_name' => __( 'Visual items', 'wcb-configurator-builder' ),
						'singular_name' => __( 'Visual item', 'wcb-configurator-builder' ),
					) )
					->add_fields( $visual_item_fields ),
			) );

	}

	/**
	 * Registers the generator for our visual post type.
	 *
	 * @since    1.0.0
	 */
	public function ajax_get_configuration_visuals() {
		check_ajax_referer('wpcb-ajax-nonce', 'nonce');

		$visuals = array();
		$conf_id = isset( $_POST['configuration_id'] ) ? sanitize_key( $_POST['configuration_id'] ) : false;
		if ( ! $conf_id ) {
			wp_send_json_success( $visuals, 200 );
			die();
		}

		if ( ! defined( 'WPCB_STRING_TRANSLATION' ) ) {
			// No string translations. Get post translation.
			if ( function_exists( 'pll_get_post' ) ) {
				$conf_id = pll_get_post( $conf_id, pll_default_language() );
			} else {
				$current_language = apply_filters( 'wpml_current_language', NULL );
				$conf_id = apply_filters( 'wpml_object_id', $conf_id, 'wpcb_configuration', true, $current_language );
			}
		}

		$meta_query = array(
			'relation' => 'AND',
			array(
				'relation' => 'OR',
				array(
					'key' => 'configuration',
					'value' => $conf_id,
					'compare' => 'LIKE'
				),
				array(
					'key' => 'configuration',
					'value' => '', // Applies to all configurations
				),
			),
		);

		$post_id = isset( $_POST['product_id'] ) ? sanitize_key( $_POST['product_id'] ) : false;
		if ( $post_id && 0 != $post_id ) {
			if ( ! defined( 'WPCB_STRING_TRANSLATION' ) ) {
				// No string translations. Get post translation.
				if ( function_exists( 'pll_get_post' ) ) {
					$post_id = pll_get_post( $post_id, pll_default_language() );
				} else {
					$post_id = apply_filters( 'wpml_object_id', $post_id, 'product', true, $current_language );
				}
			}

			$meta_query[] = array(
				'relation' => 'OR',
				array(
					'key' => 'product',
					'value' => $post_id,
					'compare' => 'LIKE'
				),
				array(
					'key' => 'product',
					'value' => '', // Applies to all configurations
				),
			);
		} else if ( ! $_POST['is_preview'] ) {
			$meta_query[] = array(
				'key' => 'product',
				'value' => '', // Applies to all configurations
			);
		}

		$show_dims = isset( $_POST['show_dims'] ) ? sanitize_key( $_POST['show_dims'] ) : 'no';
		if ( 'no' == $show_dims ) {
			$meta_query[] = array(
				'relation' => 'OR',
				array(
					'key' => '_visual_dimensions',
					'value' => 'yes',
					'compare' => '!=',
				),
				array(
					'key' => '_visual_dimensions',
					'compare' => 'NOT EXISTS',
				),
			);
		}

		if ( 'yes' === get_post_meta( $conf_id, '_include_woo_gallery', true ) && $post_id ) {
			$thumb_product_id = isset( $_POST['variation_id'] ) && 0 != $_POST['variation_id'] ? sanitize_key( $_POST['variation_id'] ) : $post_id;

			if ( ! defined( 'WPCB_STRING_TRANSLATION' ) ) {
				// No string translations. Get post translation.
				if ( function_exists( 'pll_get_post' ) ) {
					$thumb_product_id = pll_get_post( $thumb_product_id, pll_default_language() );
				} else {
					if ( isset( $_POST['variation_id'] ) && 0 != $_POST['variation_id'] ) {
						$thumb_product_id = apply_filters( 'wpml_object_id', $thumb_product_id, 'product_variation', true, $current_language );
					} else {
						$thumb_product_id = apply_filters( 'wpml_object_id', $thumb_product_id, 'product', true, $current_language );
					}
				}
			}
			
			if ( $layer = get_post_meta( $conf_id, '_woo_gallery_order', true ) ) {
				$layer = array_map( 'trim', explode(',', $layer) );
			} else {
				$layer = 10;
			}

			$default_images = array();
			$product = wc_get_product( $post_id );

			if ( $thumb_product_id !== $post_id ) {
				$variation = new WC_Product_Variation( $thumb_product_id );
				$post_thumbnail_id = $variation->get_image_id();

				if ( $post_thumbnail_id ) {
					$default_images[] = $post_thumbnail_id;
				}

				$attachment_ids = $product->get_gallery_image_ids();
				if ( $attachment_ids ) {
					$default_images = array_merge( $default_images, $attachment_ids );
				}

				foreach ( $default_images as $key => $image_id ) {
					$pos_index = $key + 1;
					$layer_index = isset( $layer[ $pos_index ] ) ? $layer[ $pos_index ] : 10; // default layer position 10 so user can place content behind

					$visuals[ $pos_index ][] = array(
						'id'    => 'base-image',
						'image' => wp_get_attachment_image_url( $image_id, 'full' ),
						'layer' => intval( $layer_index )
					);
				}
			}
		}

		$selection = isset( $_POST['selection'] ) ? map_deep( $_POST['selection'], 'sanitize_text_field' ) : array();
		$visual_type = wpcb_get_option( 'wpcb_configuration_visual_type' );
		$conf_visual_type = get_post_meta( $conf_id, '_visual_type', true ) ?: 'inherit';
		if ( 'inherit' !== $conf_visual_type ) {
			$visual_type = $conf_visual_type;
		}

		foreach ( $selection as $key => $choice ) {
			$choice_obj = $choice;

			if ( ! isset( $choice['values'] ) || ! is_array( $choice['values'] ) ) {
				continue; // Question value not selected
			}

			foreach ( $choice['values'] as $option_id => $option_val ) {
				if ( isset( $option_val['thumb'] ) && 'false' != $option_val['thumb'] ) {
					if ( 'model' === $visual_type ) {
						// 3D visual
						$type = 'material';
						if ( ! isset( $visuals[ $type ] ) || ! is_array( $visuals[ $type ] ) ) {
							$visuals[ $type ] = array();
						}

						$groups = array_map('trim', explode(',', $choice['model_group']));
						foreach ( $groups as $group ){
							$visuals[ $type ][] = array(
								'type' => $choice['model_type'],
								'name' => $group,
								'value' => $option_val['thumb'],
							);
						}
					} else {
						// 2D visual
						$position = isset( $choice['indexes'] ) ? $choice['indexes'] : 1;
						$position = array_map( 'trim', explode(',', $position) );

						$layer = isset( $choice['layers'] ) ? $choice['layers'] : 10;
						$layer = array_map( 'trim', explode(',', $layer) );

						foreach ( $position as $key => $pos_index ) {
							$layer_index = isset( $layer[ $key ] ) ? $layer[ $key ] : $layer[0];

							$thumb_details = array(
								'id'     => 'visual-' . $pos_index . '-' . $option_val['id'],
								'image'  => $option_val['thumb'],
								'layer'  => intval( $layer_index ),
								'drag'   => isset( $choice['drag'] ) ? $choice['drag'] : false,
								'top'    => isset( $choice['drag_top'] ) ? floatval( $choice['drag_top'] ) : false,
								'left'   => isset( $choice['drag_left'] ) ? floatval( $choice['drag_left'] ) : false,
								'resize' => isset( $choice['resize'] ) ? $choice['resize'] : false,
								'rotate' => isset( $choice['rotate'] ) ? $choice['rotate'] : false,
							);
			
							$visuals[ $pos_index ][] = $thumb_details;
						}
					}
				}
			}
		}

		$visual_ids = get_posts( array(
			'post_type' => 'wpcb_visual',
			'post_status' => 'publish',
			'meta_query' => $meta_query,
			'fields' => 'ids',
			'posts_per_page' => 999999,
			'suppress_filters' => false,
		));

		if ( ! $visual_ids || ! is_array( $visual_ids ) ) {
			if ( ! $post_id ) {
				wp_send_json_success( $visuals, 200 );
				die();
			}

			$visual_ids = get_posts( array(
				'post_type' => 'wpcb_visual',
				'post_status' => 'publish',
				'fields' => 'ids',
				'posts_per_page' => 999999,
				'suppress_filters' => false,
				'meta_query' => array(
					array(
						'key' => 'configuration',
						'value' => $conf_id,
						'compare' => 'LIKE'
					),
					array(
						'key' => 'product',
						'value' => '', // product empty.
					)
				),
			));
		}

		if ( ! $visual_ids || ! is_array( $visual_ids ) ) {
			wp_send_json_success( $visuals, 200 );
			die();
		}

		foreach ( $visual_ids as $visual_id ) {
			/**
			 * Check all visual posts
			 */
			$visual_items = get_post_meta( $visual_id, '_visuals', true );
			if ( ! $visual_items || count( $visual_items ) === 0 ) {
				continue;
			}

			foreach ( $visual_items as $visual_item ) {
				$total_rules = 1;
				$valid_rules = 1;
				$repeater_index = [];

				if ( isset( $visual_item['rules'] ) ) {
					$rules = $visual_item['rules'];

					$total_rules = count( $rules );
					$valid_rules = 0;

					foreach ( $rules as $rule ) {
						$choice_post_id = wpcb_get_value( $rule['choice'] );
						$choice_id = wpcb_get_value( $rule['choice'] );
						
						if ( ! defined( 'WPCB_STRING_TRANSLATION' ) ) {
							// No string translations. Get post translation.
							if ( function_exists( 'pll_get_post' ) ) {
								$choice_post_id = pll_get_post( $choice_post_id );
							} else {
								$choice_post_id = apply_filters( 'wpml_object_id', $choice_post_id, 'wpcb_choice' );
							}
						}

						$option_id = wpcb_get_value( $rule['option'] );
						$option_id = str_replace( $choice_id, $choice_post_id, $option_id );
						
						$choice_id = 'field-' . $choice_post_id;

						if ( ! array_key_exists( $choice_id, $selection ) ) {
							$found = false;
							
							foreach ( $selection as $key => $value ) {
								if ( substr($key, 0, 6) !== 'filter' && substr($key, 0, 6) !== 'repeat' && substr($key, 0, 6) !== 'group' ) {
									continue; // No repeater, filter, or group.
								}
								if ( ! isset( $value['values'] ) || ! is_array( $value['values'] ) ) {
									continue; // Question value not selected
								}

								if ( substr($key, 0, 6) !== 'repeat' ) {
									$value_id = 'field-' . explode('-', $value['values'][0]['id'])[0];
								} else {
									$value_id = 'field-' . explode('-', $value['values'][0]['values'][0]['id'])[0];
								}

								if ( $value_id == $choice_id ) {
									$choice_id = $key;
									$found = true;
								}
							}

							if ( ! $found ) {
								continue; // Question not present
							}
						}

						if ( ! isset( $selection[ $choice_id ]['values'] ) || ! is_array( $selection[ $choice_id ]['values'] ) ) {
							continue; // Question value not selected
						}

						if ( substr($choice_id, 0, 6) !== 'repeat' ) {
							$id_values = array_map( function( $value ) {
								return $value['id'];
							}, $selection[ $choice_id ]['values']);

							if ( '' !== $option_id && ! in_array( $option_id, $id_values ) ) {
								continue;
							}
							
							$choice_obj = $selection[ $choice_id ];
						} else {
							foreach ( $selection[ $choice_id ]['values'] as $index => $repeater_values ) {
								if ( isset($repeater_values['values']) && count($repeater_values['values']) > 0 ) {
									$id_values = array_map( function( $value ) {
										return isset( $value['id'] ) ? $value['id'] : '';
									}, $repeater_values['values'] );
		
									if ( '' !== $option_id && ! in_array( $option_id, $id_values ) ) {
										continue;
									}
		
									$repeater_index[] = $index;
								}
							}

							if ( count( $repeater_index ) === 0 ) {
								continue; // no repeater match.
							}

							$choice_obj = $selection[ $choice_id ];
						}

						$valid_rules++;
					}
				}

				if ( count( $rules ) > 0 ) {
					if ( ! $valid_rules || $valid_rules < $total_rules ) {
						continue;
					}
				} 

				if ( 'model' === $visual_type ) {
					// 3D visual
					$type = wpcb_get_value( $visual_item['type'] );
					if ( ! isset( $visuals[ $type ] ) || ! is_array( $visuals[ $type ] ) ) {
						$visuals[ $type ] = array();
					}

					if ( 'material' === $type ) {
						$texture_type = wpcb_get_value( $visual_item['texture_type'] );

						if ( in_array( $texture_type, array( 'metalness', 'roughness' ) ) ) {
							$groups = array_map('trim', explode(',', wpcb_get_value( $visual_item['name'] )));

							foreach ( $groups as $group ) {
								$visuals[ $type ][] = array(
									'type' => $texture_type,
									'name' => $group,
									'value' => wpcb_get_value( $visual_item['model_value'] ),
								);
							}
						} else {
							$texture_url = '';
							if ( $visual_item['texture'] ) {
								$texture_url = wp_get_attachment_image_url( wpcb_get_value( $visual_item['texture'] ), 'full' );
							}

							$groups = array_map('trim', explode(',', wpcb_get_value( $visual_item['name'] )));
							foreach ( $groups as $group ){
								$visuals[ $type ][] = array(
									'type' => $texture_type,
									'name' => $group,
									'value' => $texture_url,
								);
							}
						}
					} else if ( 'animation' === $type ) {
						$visuals[ $type ][] = array(
							'type' => wpcb_get_value( $visual_item['animation_type'] ),
							'name' => wpcb_get_value( $visual_item['model_value'] )
						);
					} else if ( 'model' === $type ) {
						$attachment_id = wpcb_get_value( $visual_item['model_file'] );
						$model_url = wpcb_get_value( $visual_item['model_value'] );
						if ( $attachment_id ) {
							$visuals[ $type ][] = wp_get_attachment_url( $attachment_id );
						} else if ( $model_url ) {
							$visuals[ $type ][] = sanitize_url( $model_url );
						}
					} else {
						// Default value pair
						$visuals[ $type ][] = wpcb_get_value( $visual_item['model_value'] );
					}

				} else if ( isset( $visual_item['image'] ) ) {

					// 2D visual
					$position = wpcb_get_value( $visual_item['index'] ) ?: 1;
					$position = array_map( 'trim', explode(',', $position) );

					$layer = wpcb_get_value( $visual_item['layer'] ) ?: 10;
					$layer = array_map( 'trim', explode(',', $layer) );

					$image_value = array();
					foreach ( $visual_item['image'] as $index => $image ) {
						$image_value[] = $image['value'];
					}

					if ( is_array( $image_value ) && count( $image_value ) > 0 ) {
						foreach ( $image_value as $key => $image_id ) {
							$pos_index = isset( $position[ $key ] ) ? $position[ $key ] : $key + 1; // default slide position 1
							$layer_index = isset( $layer[ $key ] ) ? $layer[ $key ] : $layer[0]; // default layer position 10 so user can place content behind

							if ( ! isset( $visuals[ $pos_index ] ) ) {
								$visuals[ $pos_index ] = array();
							}

							if ( ! $image_id ) {
								continue;
							}

							$image_key = 'visual-' . $pos_index . '-' . $image_id;
							if ( count( $repeater_index ) > 0 ){
								foreach ( $repeater_index as $repeater_key ) {
									$sub_item = $choice_obj['values'][ $repeater_key ];

									$image_key .= '-' . $repeater_key;

									$visuals[ $pos_index ][] = array(
										'id'    => $image_key,
										'image' => wp_get_attachment_image_url( $image_id, 'full' ),
										'layer' => intval( $layer_index ),
										'drag'   => isset( $sub_item['drag'] ) ? $sub_item['drag'] : false,
										'top'    => isset( $sub_item['drag_top'] ) ? floatval( $sub_item['drag_top'] ) : false,
										'left'   => isset( $sub_item['drag_left'] ) ? floatval( $sub_item['drag_left'] ) : false,
										'resize' => isset( $sub_item['resize'] ) ? $sub_item['resize'] : false,
										'rotate' => isset( $sub_item['rotate'] ) ? $sub_item['rotate'] : false,
									);
								}
							} else {
								$visuals[ $pos_index ][] = array(
									'id'    => $image_key,
									'image' => wp_get_attachment_image_url( $image_id, 'full' ),
									'layer' => intval( $layer_index ),
									'drag'   => isset( $choice_obj['drag'] ) ? $choice_obj['drag'] : false,
									'top'    => isset( $choice_obj['drag_top'] ) ? floatval( $choice_obj['drag_top'] ) : false,
									'left'   => isset( $choice_obj['drag_left'] ) ? floatval( $choice_obj['drag_left'] ) : false,
									'resize' => isset( $choice_obj['resize'] ) ? $choice_obj['resize'] : false,
									'rotate' => isset( $choice_obj['rotate'] ) ? $choice_obj['rotate'] : false,
								);
							}
						}
					}
				}
			}
		}

		wp_send_json_success( $visuals, 200 );
		die();
	}
}
