<?php
namespace EVPB\Tools;

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

if ( !class_exists( 'AdvancedTab' ) ) {
	class AdvancedTab {
		private const DEVICES = [ 'desktop', 'tablet', 'mobile' ];

		static function animationProps( $animation ) {
			if ( empty( $animation['type'] ) ) {
				return '';
			}

			extract( array_merge( [
				'type' => '',
				'duration' => 1,
				'delay' => 0.05,
				'once' => false,
				'mirror' => true,
				'offset' => 120,
				'easing' => 'ease',
				'anchor-placement' => 'top-bottom'
			], $animation ?? [] ) );

			$durationMs = $duration * 1000;
			$delayMs = $delay * 1000;

			$onceStr = $once ? 'true' : 'false';
			$mirrorStr = $mirror ? 'true' : 'false';
			$anchor = $animation['anchor-placement'] ?? 'top-bottom'; // Extract variable name restriction fix

			return "data-aos='$type' data-aos-duration='$durationMs' data-aos-delay='$delayMs' data-aos-once='$onceStr' data-aos-mirror='$mirrorStr' data-aos-offset='$offset' data-aos-easing='$easing' data-aos-anchor-placement='$anchor'";
		}

		static function getAdvancedAttributes( $attributes = [], $staticAttrs = [] ) {
			// Ensure inputs are arrays
			$attributes = (array) $attributes;
			$staticAttrs = (array) $staticAttrs;

			// Disallow JS event handler attributes (names starting with 'on')
			$disallowedAttrPattern = '/^on[a-z0-9_-]+/i';

			if ( ! empty( $staticAttrs ) ) {
				foreach ( $staticAttrs as $key => $value ) {
					// Smart Merge. Only concatenate 'class'.
					if ( isset( $attributes[$key] ) && ( 'class' === $key || 'className' === $key ) ) {
						$attributes[$key] = "$value " . $attributes[$key];
					} elseif ( ! isset( $attributes[$key] ) ) {
						$attributes[$key] = $value;
					}
				}
			}

			if ( empty( $attributes ) ) {
				return '';
			}

			$normalAttrs = [];
			foreach ( $attributes as $key => $value ) {
				// Skip style or empty values (but allow '0')
				if ( 'style' === $key || ( empty( $value ) && '0' !== $value ) ) {
					continue;
				}

				// Convert React 'className' to HTML 'class'
				if ( 'className' === $key ) {
					$key = 'class';
				}

				// Disallow JS event handler attributes
				if ( preg_match( $disallowedAttrPattern, $key ) ) {
					continue; // Skip JS event handler attributes
				}

				// Security escaping
				$escValue = esc_attr( $value ); // Assumes WordPress environment
				$normalAttrs[] = "$key='$escValue'";
			}

			return implode( ' ', $normalAttrs );
		}

		static function getLayoutCSS( $layout ) {
			extract( array_merge( [
				'order' => [], 
				'position' => [], 
				'inset' => []
			], $layout ?? [] ) );

			$orderCSS = fn ( $o ) => ToCSS::hasCSS( 'order', $o );
			$posCSS = fn ( $p ) => ToCSS::hasCSS( 'position', $p );

			$splitVal = fn ( $v, $i ) => explode( ' ', $v ?? '' )[$i] ?? null; // Helper for inset split
			
			$topCSS = fn ( $v ) => ToCSS::hasCSS( 'top', $splitVal( $v, 0 ) );
			$rightCSS = fn ( $v ) => ToCSS::hasCSS( 'right', $splitVal( $v, 1 ) );
			$bottomCSS = fn ( $v ) => ToCSS::hasCSS( 'bottom', $splitVal( $v, 2 ) );
			$leftCSS = fn ( $v ) => ToCSS::hasCSS( 'left', $splitVal( $v, 3 ) );

			$insetCSS = function ( $d ) use ( $position, $inset, $topCSS, $rightCSS, $bottomCSS, $leftCSS ) {
				$pos = $position[$d] ?? '';
				if ( in_array( $pos, ['relative', 'absolute', 'fixed', 'sticky'] ) ) {
					$insetVal = $inset[$d] ?? '';
					return $topCSS( $insetVal ) . $rightCSS( $insetVal ) . $bottomCSS( $insetVal ) . $leftCSS( $insetVal );
				}
				return '';
			};

			return [
				'desktop' => $orderCSS( $order['desktop'] ?? null ) . $posCSS( $position['desktop'] ?? null ) . $insetCSS( 'desktop' ),
				'tablet' => $orderCSS( $order['tablet'] ?? null ) . $posCSS( $position['tablet'] ?? null ) . $insetCSS( 'tablet' ),
				'mobile' => $orderCSS( $order['mobile'] ?? null ) . $posCSS( $position['mobile'] ?? null ) . $insetCSS( 'mobile' ),
			];
		}

		static function getDimensionCSS( $dimension ){
			$minWidth = $dimension['min-width'] ?? [];
			$width = $dimension['width'] ?? [];
			$maxWidth = $dimension['max-width'] ?? [];
			$minHeight = $dimension['min-height'] ?? [];
			$height = $dimension['height'] ?? [];
			$maxHeight = $dimension['max-height'] ?? [];
			$padding = $dimension['padding'] ?? [];
			$margin = $dimension['margin'] ?? [];

			$minWCSS = fn ( $w ) => ToCSS::hasCSS( 'min-width', ToCSS::autoOrVal( $w ) );
			$wCSS = fn ( $w ) => ToCSS::hasCSS( 'width', ToCSS::autoOrVal( $w ) );
			$maxWCSS = fn ( $w ) => ToCSS::hasCSS( 'max-width', ToCSS::autoOrVal( $w ) );
			$minHCSS = fn ( $h ) => ToCSS::hasCSS( 'min-height', ToCSS::autoOrVal( $h ) );
			$hCSS = fn ( $h ) => ToCSS::hasCSS( 'height', ToCSS::autoOrVal( $h ) );
			$maxHCSS = fn ( $h ) => ToCSS::hasCSS( 'max-height', ToCSS::autoOrVal( $h ) );
			$pCSS = fn ( $p ) => ToCSS::hasCSS( 'padding', $p );
			$mCSS = fn ( $m ) => ToCSS::hasCSS( 'margin', $m );

			$parent = [];
			foreach ( self::DEVICES as $device ) {
				$parent[$device] =
					$minWCSS( $minWidth[$device] ?? null ) .
					$wCSS( $width[$device] ?? null ) .
					$maxWCSS( $maxWidth[$device] ?? null ) .
					$minHCSS( $minHeight[$device] ?? null ) .
					$hCSS( $height[$device] ?? null ) .
					$maxHCSS( $maxHeight[$device] ?? null );
			}

			$selector = [];
			foreach ( self::DEVICES as $device ) {
				$selector[$device] =
					$pCSS( $padding[$device] ?? null ) .
					$mCSS( $margin[$device] ?? null );
			}

			return ['parent' => $parent, 'selector' => $selector];
		}

		static function getBackgroundCSS( $selector = '', $background, $transitions = '' ) {
			extract( array_merge( [
				'normal' => '', 
				'hover' => '', 
				'filter' => '', 
				'hoverFilter' => '', 
				'backdropFilter' => '', 
				'hoverBackdropFilter' => ''
			], $background ?? [] ) );

			$bgCSS = fn ( $b ) => ( $b && 'background-color: ;' !== $b ) ? ToCSS::cleanBGDetail( $b ) : '';
			$fCSS = fn ( $f ) => ToCSS::hasCSS( 'filter', $f );
			$bfCSS = fn ( $bf ) => ToCSS::hasCSS( 'backdrop-filter', $bf ) . ToCSS::hasCSS( '-webkit-backdrop-filter', $bf );

			$filterCSS = $fCSS( $filter ) . $bfCSS( $backdropFilter ) . $fCSS( $hoverFilter ) . $bfCSS( $hoverBackdropFilter );
			$normalCSS = $bgCSS( $normal ) . $fCSS( $filter ) . $bfCSS( $backdropFilter );
			$hoverCSS = $bgCSS( $hover ) . $fCSS( $hoverFilter ) . $bfCSS( $hoverBackdropFilter );

			$transition = '';
			if ( ! empty( $transitions ) ) {
				$parts = explode( ', ', $transitions );
				foreach( $parts as $part ) {
					if ( 0 === strpos( $part, 'background' ) ) {
						$transition = $part ? str_replace( 'background', 'all', $part ) : '';
						break;
					}
				}
			}
			$transitionCSS = ToCSS::hasCSS( 'transition', $transition );

			return [
				'normal' => ToCSS::isEmpty( $filterCSS ) ? $bgCSS( $normal ) . $fCSS( $filter ) . $bfCSS( $backdropFilter ) : '',
				'hover' => ToCSS::isEmpty( $filterCSS ) ? $bgCSS( $hover ) . $fCSS( $hoverFilter ) . $bfCSS( $hoverBackdropFilter ) : '',
				'pseudo' => ToCSS::isEmpty( $filterCSS ) ? '' : "
					$selector {
						position: relative;
					}
					$selector::before {
						content: '';
						position: absolute;
						inset: 0 0 0 0;
						width: 100%;
						height: 100%;
						$normalCSS
						$transitionCSS
					}
					$selector:hover::before {
						$hoverCSS
					}
				"
			];
		}

		static function getOverlayCSS( $selector = '', $overlay ) {
			if ( empty( $overlay['isEnabled'] ) ) {
				return '';
			}

			extract( array_merge( [
				'normal' => [], 
				'hover' => [], 
				'transition' => null
			], $overlay ?? [] ) );

			$getOvCSS = function ( $state ) {
				if ( empty( $state ) ) return '';
				
				$opacity = $state['opacity'] ?? null;
				$bg = $state['bg'] ?? '';
				$mixBlendMode = $state['mix-blend-mode'] ?? null;
				$filter = $state['filter'] ?? null;
				$backdropFilter = $state['backdrop-filter'] ?? null;

				return ToCSS::hasCSS( 'opacity', $opacity ) .
					( 'background-color: ;' === $bg ? '' : ToCSS::cleanBGDetail( $bg ) ) .
					ToCSS::hasCSS( 'mix-blend-mode', $mixBlendMode ) .
					ToCSS::hasCSS( 'filter', $filter ) .
					ToCSS::hasCSS( 'backdrop-filter', $backdropFilter ) .
					ToCSS::hasCSS( '-webkit-backdrop-filter', $backdropFilter );
			};

			$normalCSS = $getOvCSS( $normal );
			$hoverCSS = $getOvCSS( $hover );
			$transitionCSS = ToCSS::hasCSS( 'transition', $transition );

			return "
				$selector{
					position: relative;
				}
				$selector::after {
					content: '';
					position: absolute;
					inset: 0 0 0 0;
					width: 100%;
					height: 100%;
					$normalCSS
					$transitionCSS
				}
				$selector:hover::after {
					$hoverCSS
				}
			";
		}

		static function getVisualCSS( $visual ) {
			$overflow = $visual['overflow'] ?? [];
			$zIndex = $visual['z-index'] ?? [];
			$pointerEvents = $visual['pointer-events'] ?? [];
			$cursor = $visual['cursor'] ?? [];
			$visibility = $visual['visibility'] ?? [];
			$opacity = $visual['opacity'] ?? [];

			$oCSS = fn ( $o ) => ToCSS::hasCSS( 'overflow', $o );
			$zCSS = fn ( $z ) => ToCSS::hasCSS( 'z-index', $z );
			$peCSS = fn ( $p ) => ToCSS::hasCSS( 'pointer-events', $p );
			$cCSS = fn ( $c ) => ToCSS::hasCSS( 'cursor', $c );
			$vCSS = fn ( $v ) => ToCSS::hasCSS( 'visibility', $v );
			$opCSS = fn ( $o ) => ToCSS::hasCSS( 'opacity', $o );

			$normal = [];
			foreach ( self::DEVICES as $device ) {
				$normal[$device] =
					$oCSS( $overflow[$device] ?? null ) .
					$zCSS( $zIndex[$device] ?? null ) .
					$vCSS( $visibility[$device] ?? null );
			}

			$selectorNormal = [];
			foreach ( self::DEVICES as $device ) {
				$selectorNormal[$device] = $peCSS( $pointerEvents[$device] ?? null ) . $cCSS( $cursor[$device] ?? null ) . $opCSS( $opacity['normal'][$device] ?? null );
			}
			$selectorHover = [];
			foreach ( self::DEVICES as $device ) {
				$selectorHover[$device] = $opCSS( $opacity['hover'][$device] ?? null );
			}

			return array_merge( $normal, [ 'normal' => $selectorNormal, 'hover' => $selectorHover ] );
		}

		static function getFrameCSS( $frame ) {
			$stateCSS = function ( $f ) {
				if ( empty( $f ) ) return '';

				extract( array_merge( [
					'border' => [], 
					'radius' => '', 
					'shadow' => ''
				], $f ?? [] ) );

				$radiusCSS = $radius ? "border-radius: $radius;" : '';
				$shadowCSS = $shadow ? "box-shadow: $shadow;" : '';
				return ToCSS::borderCSS( $border ) . $radiusCSS . $shadowCSS;
			};

			return [
				'normal' => $stateCSS( $frame['normal'] ?? null ),
				'hover' => $stateCSS( $frame['hover'] ?? null ),
			];
		}

		static function getTransformCSS( $selector = '', $transform ) {
			extract( array_merge( [
				'normal' => '', 
				'hover' => '', 
				'infinite' => null
			], $transform ?? [] ) );

			$selectorKey = $selector ? explode( ' ', $selector )[0] : '';
			$animationName = $selector ? 'infiniteTransform-' . preg_replace( '/[^a-zA-Z0-9]/', '', $selectorKey ) : 'infiniteTransform';

			$keyframes = '';
			if ( !empty( $infinite['css'] ) ) {
				$keyframes = "
					@-webkit-keyframes $animationName { to { ". $infinite['css'] ." } }
					@keyframes $animationName { to { ". $infinite['css'] ." } }
				";
			}

			$normalCSS = '';
			if ( !empty( $infinite['css'] ) ) {
				$duration = $infinite['duration'] ?? '2s';
				$timingFunction = $infinite['timingFunction'] ?? 'ease';
				$direction = $infinite['direction'] ?? 'normal';
				$property = "$animationName $duration $timingFunction infinite $direction";
				$normalCSS = "-webkit-animation: $property; animation: $property;";
			}

			return [
				'normal' => "$normal $normalCSS",
				'hover' => $hover,
				'keyframes' => $keyframes,
			];
		}

		static function getMaskCSS( $mask ) {
			if ( empty( $mask['shape'] ) ) return '';

			extract( array_merge( [
				'shape' => '',
				'gradient' => '',
				'custom' => '',
				'size' => 'contain',
				'position' => 'center center',
				'repeat' => ''
			], $mask ?? [] ) );

			$shapeCSSVal = '';
			if ( $shape === 'custom' ) {
				$shapeCSSVal = "url( $custom )";
			} elseif ( $shape === 'gradient' ) {
				$shapeCSSVal = $gradient;
			} else {
				$shapeCSSVal = 'url( data:image/svg+xml;base64,' . base64_encode( $shape ) . ' )';
			}

			return ToCSS::hasCSS( '-webkit-mask-image', $shapeCSSVal ) .
				ToCSS::hasCSS( 'mask-image', $shapeCSSVal ) .
				ToCSS::hasCSS( '-webkit-mask-size', $size ) .
				ToCSS::hasCSS( 'mask-size', $size ) .
				ToCSS::hasCSS( '-webkit-mask-position', $position ) .
				ToCSS::hasCSS( 'mask-position', $position ) .
				ToCSS::hasCSS( '-webkit-mask-repeat', $repeat ) .
				ToCSS::hasCSS( 'mask-repeat', $repeat );
		}

		static function getResponsiveCSS( $responsive ) {
			extract( array_merge( [
				'desktop' => false, 
				'tablet' => false, 
				'mobile' => false
			], $responsive ?? [] ) );

			return [
				'desktop' => $desktop ? 'display: none;' : 'display: block;',
				'tablet' => $tablet ? 'display: none;' : 'display: block;',
				'mobile' => $mobile ? 'display: none;' : 'display: block;',
			];
		}

		static function getTransitionCSS( $advanced ) {
			extract( array_merge( [
				'background' => [], 
				'frame' => [], 
				'transitions' => null
			], $advanced ?? [] ) );

			$bgTr = $background['transition'] ?? 0.5;
			$frTr = $frame['transition'] ?? 0.5;

			if ( null === $transitions || empty( $transitions ) ) {
				$transitions = "color {$bgTr}s, background {$bgTr}s, border {$frTr}s, border-radius {$frTr}s, box-shadow {$frTr}s, text-shadow {$frTr}s, transform 0.5s";
			}

			return ToCSS::hasCSS( '-webkit-transition', $transitions ) . ToCSS::hasCSS( 'transition', $transitions );
		}

		static function generateCSS( $parent, $selector = '', $advanced ) {
			extract( array_merge( [
				'layout' => [],
				'dimension' => [],
				'background' => [],
				'overlay' => [],
				'visual' => [],
				'frame' => [],
				'transform' => [],
				'mask' => [],
				'responsive' => [],
				'transitions' => '',
				'css' => ''
			], $advanced ?? [] ) );

			$layoutCSS = self::getLayoutCSS( $layout );
			$dimensionCSS = self::getDimensionCSS( $dimension );
			$visualCSS = self::getVisualCSS( $visual );
			$backgroundCSS = self::getBackgroundCSS( $selector, $background, $transitions );
			$frameCSS = self::getFrameCSS( $frame );
			$transformCSS = self::getTransformCSS( $selector, $transform );
			$maskCSS = self::getMaskCSS( $mask );
			$responsiveCSS = self::getResponsiveCSS( $responsive );
			$transitionCSS = self::getTransitionCSS( $advanced );

			$parentCSS = [];
			$selectorCSS = [];
			$selectorHovCSS = [];

			foreach ( self::DEVICES as $device ) {
				$parentCSS[$device] = $layoutCSS[$device] . $dimensionCSS['parent'][$device] . ( $visualCSS[$device] ?? '' ) . $responsiveCSS[$device] . ( $device === 'desktop' ? $maskCSS : '' );

				$selectorCSS[$device] = $dimensionCSS['selector'][$device] . ( $visualCSS['normal'][$device] ?? '' ) . ( $device === 'desktop' ? $backgroundCSS['normal'] . $frameCSS['normal'] . $transformCSS['normal'] . $transitionCSS : '' );

				$selectorHovCSS[$device] = ( $visualCSS['hover'][$device] ?? '' ) . ( $device === 'desktop' ? $backgroundCSS['hover'] . $frameCSS['hover'] . $transformCSS['hover'] : '' );
			}

			$deviceCSS = '';
			foreach ( self::DEVICES as $device ) {
				$breakpoint = $device === 'tablet' ? Helper::TAB_BREAKPOINT : ( $device === 'mobile' ? Helper::MOB_BREAKPOINT : '' );
				$pCSS = $parentCSS[$device];
				$sCSS = $selectorCSS[$device];
				$shCSS = $selectorHovCSS[$device];

				if ( !$pCSS && !$sCSS && !$shCSS ) continue;

				$innerCSS = '';
				if ( $pCSS ) $innerCSS .= "$parent { $pCSS }";
				if ( $sCSS ) $innerCSS .= "$selector { $sCSS }";
				if ( $shCSS ) $innerCSS .= "$selector:hover { $shCSS }";

				$deviceCSS .= $breakpoint ? "$breakpoint { $innerCSS }" : $innerCSS;
			}

			$finalCSS = $transformCSS['keyframes'] . $deviceCSS . $backgroundCSS['pseudo'] . self::getOverlayCSS( $selector, $overlay );

			if ( $css ) {
				$finalCSS .= str_replace( 'selector', $parent, $css );
			}

			return preg_replace( '/\s+/', ' ', trim( $finalCSS ) );
		}
	}
}