<?php
namespace BricksUltimate\Elements;

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

use BricksUltimate\Helpers;
use BricksUltimate\Trait\TooltipControls;

class WooLinkedVariations extends \Bricks\Element {
	use TooltipControls;

	public $category 	= 'ultimate';
	public $name 		= 'bu-linked-variations';
	public $icon 		= 'ti-link';

	/**
	 * Linked Attributes Data.
	 *
	 * @var array
	 */
	private $linked_data = [];

	// Return localized element label
	public function get_label() {
		return esc_html__( '(BU)Linked Variations', 'bricksultimate' );
	}

		// Set builder control groups
	public function set_control_groups() {
		$this->control_groups['swatch'] = array(
			'title' 	=> esc_html__( 'Swatches', 'bricks' ),
			'tab'   	=> 'content'
		);

		$this->control_groups['tooltip'] = array(
			'title' 	=> esc_html__( 'Tooltip', 'bricks' ),
			'tab'   	=> 'content'
		);
	}

	// Set builder controls
	public function set_controls() {
		$this->controls['swWhiteTick'] = [
			'type' 	=> 'checkbox',
			'label' => esc_html__( 'Disable white tick icon', 'bricksultimate' ),
		];

		$this->controls['swHideLabel'] = [
			'type' 	=> 'checkbox',
			'label' => esc_html__( 'Hide label', 'bricksultimate' ),
		];

		$this->controls['showActiveLabel'] = [
			'type' 	=> 'checkbox',
			'label' => esc_html__( 'Display active variation label', 'bricksultimate' ),
		];

		$this->controls['swShowName'] = [
			'type' 	=> 'checkbox',
			'label' => esc_html__( 'Display swatch + name', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' 	=> 'display',
					'selector' 	=> '.bu-swatch-label',
					'value' 	=> 'block;'
				]
			]
		];

		$this->controls['variationsPos'] = [
			'type' 	=> 'checkbox',
			'label' => esc_html__( 'Variations placement', 'bricksultimate' ),
			'label' => esc_html__( 'Display the variations under the label.', 'bricksultimate' ),
			'required' => ['showActiveLabel', '!=', true]
		];

		$this->controls['swLabelTypography'] = [
			'type' 	=> 'typography',
			'label' => esc_html__( 'Label typography', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'font',
					'selector' => 'label',
				]
			],
			'required' => ['swHideLabel', '!=', true]
		];

		$this->controls['activeLabelFont'] = [
			'type' 	=> 'typography',
			'label' => esc_html__( 'Swatch name typography', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'font',
					'selector' => '.bu-swatch-label',
				]
			],
			'required' => ['swShowName', '=', true]
		];

		$this->controls['activeLabelFont'] = [
			'type' 	=> 'typography',
			'label' => esc_html__( 'Active label typography', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'font',
					'selector' => '.bulv-active-label',
				]
			],
			'required' => ['showActiveLabel', '=', true]
		];

		$this->controls['labelGap'] = [
			'type' 	=> 'number',
			'label' => esc_html__( 'Gap', 'bricksultimate' ),
			'description' => esc_html__( 'Gap between label & variations', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '8px',
			'css' 	=> [
				[
					'property' => 'gap',
					'selector' => '.linked-product-wrap'
				]
			],
		];

		$this->controls['swOuterBrd'] = [
			'group' => 'swatch',
			'type' 	=> 'border',
			'label' => esc_html__( 'Wrapper border', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'border',
					'selector' => '.bu-swatch.bu-swatch-with-name'
				]
			],
			'exclude' => ['border-radius']
		];

		$this->controls['swWrapPad'] = [
			'group' => 'swatch',
			'type' 	=> 'dimensions',
			'label' => esc_html__( 'Wrapper padding', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'padding',
					'selector' => '.bu-swatch-with-name.swatch-with-bg'
				]
			],
			'required' => ['swShowName', '=', true]
		];

		$this->controls['swDisable'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Opacity', 'bricksultimate' ),
			'description' => esc_html__( 'Disabled swatches', 'bricksultimate' ),
			'unitless' => true,
			'min' 	=> 0,
			'max' 	=> 1,
			'step' => 0.1,
			'placeholder' => 0.75,
			'css' 	=> [
				[
					'property' => 'opacity',
					'selector' => '.swatch-disabled'
				]
			]
		];

		$this->controls['swGap'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Gap', 'bricksultimate' ),
			'description' => esc_html__( 'Between swatches', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '8px',
			'css' 	=> [
				[
					'property' => 'margin-right',
					'selector' => '.bu-swatch:not(last-child)'
				]
			]
		];

		$this->controls['swColorSep'] = [
			'group' => 'swatch',
			'type' 	=> 'separator',
			'label' => esc_html__( 'Color swatches', 'bricksultimate' ),
		];

		$this->controls['swColorW'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Width', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '18px',
			'css' 	=> [
				[
					'property' => 'width',
					'selector' => '.swatch-with-bg.swatches-color span'
				]
			]
		];

		$this->controls['swColorH'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Height', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '18px',
			'css' 	=> [
				[
					'property' => 'height',
					'selector' => '.swatch-with-bg.swatches-color span'
				]
			]
		];

		$this->controls['swColorbrd'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Border radius', 'bricksultimate' ),
			'units' => true,
			'css' 	=> [
				[
					'property' => 'border-radius',
					'selector' => '.swatch-with-bg.swatches-color, .swatch-with-bg.swatches-color span'
				]
			]
		];

		$this->controls['swImgSep'] = [
			'group' => 'swatch',
			'type' 	=> 'separator',
			'label' => esc_html__( 'Image swatches', 'bricksultimate' ),
		];

		$this->controls['swImgW'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Width', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '25px',
			'css' 	=> [
				[
					'property' => 'width',
					'selector' => '.swatch-with-bg.swatches-image span'
				]
			]
		];

		$this->controls['swImgH'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Height', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '25px',
			'css' 	=> [
				[
					'property' => 'height',
					'selector' => '.swatch-with-bg.swatches-image span'
				]
			]
		];

		$this->controls['swImgbrd'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Border radius', 'bricksultimate' ),
			'units' => true,
			'placeholder' => '0px',
			'css' 	=> [
				[
					'property' => 'border-radius',
					'selector' => '.swatch-with-bg.swatches-image, .swatch-with-bg.swatches-image span'
				]
			]
		];

		$this->controls['swTextSep'] = [
			'group' => 'swatch',
			'type' 	=> 'separator',
			'label' => esc_html__( 'Text swatches', 'bricksultimate' ),
		];

		$selector = '.bu-swatch:not(.swatch-with-bg) span';

		$this->controls['swTextW'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Width', 'bricksultimate' ),
			'units' => true,
			'css' 	=> [
				[
					'property' => 'width',
					'selector' => $selector
				]
			]
		];

		$this->controls['swTextH'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Height', 'bricksultimate' ),
			'units' => true,
			'css' 	=> [
				[
					'property' => 'height',
					'selector' => $selector
				]
			]
		];

		$this->controls['swTextFont'] = [
			'group' => 'swatch',
			'type' 	=> 'typography',
			'label' => esc_html__( 'Typography', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'font',
					'selector' => $selector
				]
			]
		];

		$this->controls['swTextBg'] = [
			'group' => 'swatch',
			'type' 	=> 'color',
			'label' => esc_html__( 'Background', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'background-color',
					'selector' => $selector
				]
			]
		];

		$this->controls['swTextbrd'] = [
			'group' => 'swatch',
			'type' 	=> 'number',
			'label' => esc_html__( 'Border radius', 'bricksultimate' ),
			'units' => true,
			'css' 	=> [
				[
					'property' => 'border-radius',
					'selector' => $selector
				]
			]
		];

		$this->controls['swTextPad'] = [
			'group' => 'swatch',
			'type' 	=> 'dimensions',
			'label' => esc_html__( 'Padding', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'padding',
					'selector' => $selector
				]
			]
		];

		$this->controls['swHoverSep'] = [
			'group' => 'swatch',
			'type' 	=> 'separator',
			'label' => esc_html__( 'Hover swatches', 'bricksultimate' ),
		];

		$this->controls['swTextHBg'] = [
			'group' => 'swatch',
			'type' 	=> 'color',
			'label' => esc_html__( 'Background', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'background-color',
					'selector' => '.bu-swatch:not(.swatch-with-bg):hover span'
				]
			]
		];

		$this->controls['swTextHClr'] = [
			'group' => 'swatch',
			'type' 	=> 'color',
			'label' => esc_html__( 'Text color', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'color',
					'selector' => '.bu-swatch:not(.swatch-with-bg):hover span'
				]
			]
		];

		$this->controls['swHBrd'] = [
			'group' => 'swatch',
			'type' 	=> 'border',
			'label' => esc_html__( 'Border', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'border',
					'selector' => '.bu-swatch:hover'
				]
			],
			'exclude' => ['border-radius']
		];

		$this->controls['swActiveSep'] = [
			'group' => 'swatch',
			'type' 	=> 'separator',
			'label' => esc_html__( 'Active swatches', 'bricksultimate' ),
		];

		$this->controls['swTextABg'] = [
			'group' => 'swatch',
			'type' 	=> 'color',
			'label' => esc_html__( 'Background', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'background-color',
					'selector' => '.active-swatch.bu-swatch:not(.swatch-with-bg) span'
				]
			]
		];

		$this->controls['swTextAClr'] = [
			'group' => 'swatch',
			'type' 	=> 'color',
			'label' => esc_html__( 'Text color', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'color',
					'selector' => '.active-swatch.bu-swatch:not(.swatch-with-bg) span'
				]
			]
		];

		$this->controls['swActiveBrd'] = [
			'group' => 'swatch',
			'type' 	=> 'border',
			'label' => esc_html__( 'Border', 'bricksultimate' ),
			'css' 	=> [
				[
					'property' => 'border',
					'selector' => '.bu-swatch.active-swatch'
				]
			],
			'exclude' => ['border-radius']
		];

		$this->controls = $this->bu_tooltip_controls( $this->controls, 'tooltip' );
	}

	// Enqueue element styles and scripts
	public function enqueue_scripts() {
		if( ! Helpers::isBricksBuilderEditor() ) {
			wp_enqueue_script( 'bu-swatches' );
		}

		if( isset($this->settings['hasTooltip']) ) {
			wp_enqueue_style( 'bu-tooltip' );
			wp_enqueue_script( 'bu-popper' );
			wp_enqueue_script( 'bu-tippy' );
		}
	}

	// Render element HTML
	public function render() {
		global $product;

		$product = wc_get_product( $this->post_id );

		if( $product === false )
			return;

		$settings = $this->settings;

		$this->set_linked_variations_data( $product->get_id() );

		if ( empty( $this->linked_data ) || ! $this->linked_data['atts'] || 1 === count( $this->linked_data['atts'] ) && empty( reset( $this->linked_data['atts'] ) ) ) {
			return;
		}

		$current_attributes = $product->get_attributes();
		$link_products = array_diff( $this->linked_data['products'], [ $product->get_id() ] );

		if( ! empty( $settings['swWhiteTick'] ) ){
			$this->set_attribute( '_root', 'class', [ 'no-tick' ] );
		}

		if( ! empty( $settings['showActiveLabel'] ) ){
			$this->set_attribute( '_root', 'class', [ 'show-active-label' ] );
		}

		if( ! empty( $settings['variationsPos'] ) ){
			$this->set_attribute( '_root', 'class', [ 'atts-below-label' ] );
		}

		if( ! empty( $settings['hasTooltip'] ) ) {
			$data = [
				'hasTooltip' => 'yes',
				'animation' => Helpers::get_value($settings, 'ttAnimation', 'perspective'),
				'placement' => Helpers::get_value($settings, 'ttPlacement', 'top')
			];

			$this->set_attribute( '_root',  "data-tooltip-config", wp_json_encode( $data ) );
		}
		
		$output = "<{$this->tag} {$this->render_attributes('_root')}>";

		foreach( $this->linked_data['atts'] as $taxonomy ) {
			$swatches = $this->get_active_swatches( $taxonomy );
			$linked_products = [];
			$activeLabel = '';

			if( ! empty( $settings['showActiveLabel'] ) ) {
				foreach ( $swatches as $swatch ) {
					if ( $current_attributes && in_array( $swatch->term_id, $current_attributes[$taxonomy]->get_options() ) ) {
						$activeLabel = '<span class="bulv-active-label">' . get_term_by('id', $swatch->term_id, $taxonomy )->name . '</span>';
						break;
					}
				}
			}

			$output .= '<div class="linked-product-wrap">';

			if( empty( $settings['swHideLabel']) ) {
				$output .= sprintf('<label>%s : %s</label>', wc_attribute_label( $taxonomy, $product ), $activeLabel );
			} elseif( $activeLabel ) {
				echo $activeLabel;
			}

			$output .= '<div class="bu-swatches bu-swatches-product">';

			foreach ( $swatches as $swatch ) {
				if ( $current_attributes && in_array( $swatch->term_id, $current_attributes[$taxonomy]->get_options() ) ) {
					$output .= $this->build_swatches( $swatch, $product->get_id(), true, $taxonomy );
				} else {
					$tax_dump = [];
					$tax_query = [
						'taxonomy' => $taxonomy,
						'term'     => $swatch->slug
					];

					foreach ( array_keys( $current_attributes ) as $product_attribute ) {
						if ( ! in_array( $product_attribute, $this->linked_data['atts'] ) ) {
							continue;
						}

						if ( $taxonomy != $product_attribute ) {
							$tax_dump[] = [
								'taxonomy' => $product_attribute,
								'term'     => $current_attributes[$product_attribute]->get_options()[0]
							];
						}
					}

					array_push( $tax_dump, $tax_query );

					if ( $linked_id = $this->get_linked_product_id( $tax_dump, $link_products, $linked_products ) ) {
						$linked_products[] = $linked_id;
						$output .= $this->build_swatches( $swatch, $linked_id, false, $taxonomy );
					} elseif( $linked_id = $this->get_linked_product_id( [ $tax_query ], $link_products, $linked_products ) ) {
						$linked_products[] = $linked_id;
						$output .= $this->build_swatches( $swatch, $linked_id, false, $taxonomy );
					}
				}
			}

			$output .= '</div>';
			//* end swatches

			$output .= '</div>';
		}

		$output .= "</{$this->tag}>";

		echo $output;
	}

	public function get_linked_product_id( $tax_query, $link_products = [], $linked_products = [] ) {
		$get_products = array_diff( $link_products, $linked_products );

		foreach ( $get_products as $productId ) {
			$valid = true;

			foreach ( $tax_query as $tax ) {
				if ( ! has_term( $tax['term'], $tax['taxonomy'], $productId ) ) {
					$valid = false;
					break;
				}
			}

			if ( $valid ) {
				return $productId;
			}
		}

		return false;
	}

	private function get_active_swatches( $taxonomy ) {
		$taxonomy_ids = [];

		// Fetch attributes
		foreach ( $this->linked_data['products'] as $linked_product_id ) {
			$product = wc_get_product( $linked_product_id );

			if ( ! $product || $product->get_status() !== 'publish' ) {
				continue;
			}

			$product_atts = $product->get_attributes();

			if ( is_wp_error( $product_atts ) || empty( $product_atts[ $taxonomy ] ) || ! $product_atts[ $taxonomy ]->get_options() ) {
				continue;
			}

			$taxonomy_ids = array_merge( $taxonomy_ids, $product_atts[ $taxonomy ]->get_options() );
		}

		$terms = get_terms(
			[
				'taxonomy' => $taxonomy,
				'include'  => array_unique( $taxonomy_ids ),
				'order'  => 'term_order',
			]
		);

		foreach( $terms as $key => $term ) {
			$term->meta =  [
				'color' 	=> get_term_meta( $term->term_id, 'bu_swatches_color', true ),
				'image' 	=> get_term_meta( $term->term_id, 'bu_swatches_img_id', true ),
				'brxclr' 	=> get_term_meta( $term->term_id, 'bricks_swatch_color_value', true ),
				'brximg' 	=> get_term_meta( $term->term_id, 'bricks_swatch_image_value', true )
			];
		}

		return $terms;
	}

	private function build_swatches( $swatch, $product_id, $isActive, $taxonomy ) {
		$product = wc_get_product( $product_id );

		if( $product == false )
			return '';

		$style = $output = '';
		$class = 'bu-swatch swatch-on-single ';

		$onlyText = ! empty( $this->linked_data['atts_text'] ) && in_array( $taxonomy, $this->linked_data['atts_text']);
		$featuredImage = ! empty( $this->linked_data['atts_image'] ) && in_array( $taxonomy, $this->linked_data['atts_image'] );

		if( $featuredImage ) {
			$class .= 'swatch-with-bg swatches-image';
			$hasBg = true;
		} elseif( ( ! empty( $swatch->meta['color'] ) || ! empty( $swatch->meta['brxclr'] ) ) && ! $onlyText ) {
			$class .= 'swatch-with-bg swatches-color';
			$style = 'background-color:' . $swatch->meta['color'] ?? $swatch->meta['brxclr'];
			$hasBg = true;
		} elseif ( ( ! empty( $swatch->meta['image'] ) || ! empty( $swatch->meta['brximg'] ) ) && ! $onlyText ) {
			//* swatch image
			$image = wp_get_attachment_image_url( $swatch->meta['image'] ?? $swatch->meta['brximg'], 'shop_thumbnail' );
			$class .= 'swatch-with-bg swatches-image';
			$style = 'background-image: url(' . $image . ')';
			$hasBg = true;
		} else {
			$hasBg = false;
		}

		if( ! empty( $this->settings['swShowName'] ) ){
			$class .= ' bu-swatch-with-name';
		}

		if( $isActive ) {
			$class .= ' active-swatch';
		}

		if ( 'outofstock' === $product->get_stock_status() || ! $product->is_purchasable() ) {
			$class .= ' swatch-disabled';
		} else {
			$class .= ' swatch-enabled';
		}

		$output .= '<a class="' . esc_attr( $class ) .'" href="' . esc_url( get_permalink( $product_id ) ) .'" role="button" data-title="' . $swatch->name . '">';

		if( $product->get_image_id() && $featuredImage ) {
			$thumb = wp_get_attachment_image( $product->get_image_id(), 'shop_thumbnail');
			if ( ! empty( $thumb ) ) {
				$output .= '<span class="bulv-featured-image">' . $thumb . '</span>';
			}
		} elseif( $hasBg === true ) {
			$output .= '<span style="' . esc_attr( $style ) .'">' . $swatch->name . '</span><label class="bu-swatch-label">' . $swatch->name . '</label>';
		} else {
			$output .= '<span class="bu-swatch-atts-label">' . $swatch->name . '</span>';
		}

		$output .= '</a>';

		return $output;
	}

	private function set_linked_variations_data( $product_id ) {
		$result = \BricksUltimate\WooCommerce\WooLinkedProducts::get_instance()->isLinkedProduct( $product_id );
		if( $result ) {
			$this->linked_data = [
				'products'  => get_post_meta( $result->ID, '_bulv_products', true ),
				'atts'      => get_post_meta( $result->ID, '_bulv_attributes', true ),
				'atts_text' => get_post_meta( $result->ID, '_bulv_attributes_only_text', true ),
				'atts_image' => get_post_meta( $result->ID, '_bulv_attributes_image', true )
			];
		}

		return;
	}
}