<?php


namespace Hecate\Style;

/*
 * Group styles based on the styled components, uses rules to group style on the same selector(same styled component)
 */

use Hecate\Lodash;

class RulesManager {

	private $rules              = array();
	private $rootSelector       = '';
	private $componentParts     = array();
	private $componentPartsById = array();
	private $baseStyle          = array();
	public function __construct( $rootSelector, $componentParts ) {
		$this->rootSelector       = $rootSelector;
		$this->componentParts     = $componentParts;
		$this->componentPartsById = Lodash::keyBy( $componentParts, 'id' );
	}

	public function getRules() {
		return $this->rules;
	}

	public function addRule( $style, $componentPart, $options = array() ) {
		if ( empty( $style ) ) {
			return;
		}

		$options = Lodash::merge(
			array(
				'media'           => Constants::MEDIA_DESKTOP,
				'state'           => Constants::STATE_NORMAL,
				'componentPartId' => $componentPart['id'],
			),
			$options
		);

		$rule = $this->getRuleByComponentPart( $options );
		if ( ! $rule ) {
			$rule          = new Rule( $style, $options );
			$this->rules[] = $rule;
		} else {
			$rule->addStyle( $style );
		}
	}

	public function getRuleByComponentPart( $options ) {
		$result = null;
		foreach ( $this->rules as $rule ) {
			if ( $rule->ruleMatchesQuery( $options['componentPartId'], $options['media'], $options['state'] ) ) {
				$result = $rule;
			}
		}

		return $result ? $result : null;
	}

	public function generateCSS() {
		$css   = '';
		$rules = $this->getOrderedRules();
		foreach ( $rules as $rule ) {
			$css .= $this->generateRuleStyle( $rule );
		}

		return $css;
	}

	public function getOrderedRules() {
		$rules           = $this->rules;
		$normalRules     = array();
		$stateRules      = array();
		$mediaRules      = array();
		$mediaStateRules = array();
		foreach ( $rules as $rule ) {
			$state = $rule->getState();
			$media = $rule->getMedia();
			if ( $state !== Constants::STATE_NORMAL && $media !== Constants::MEDIA_DESKTOP ) {
				$mediaStateRules[] = $rule;
				continue;
			}
			if ( $state !== Constants::STATE_NORMAL ) {
				$stateRules[] = $rule;
				continue;
			}
			if ( $media !== Constants::MEDIA_DESKTOP ) {
				$mediaRules[] = $rule;
				continue;
			}

			$normalRules[] = $rule;
		}

		return array_merge( $normalRules, $stateRules, $mediaRules, $mediaStateRules );
	}

	public function getComponentPartselector( $rule ) {
		$componentPartId       = $rule->getComponentPartId();
		$componentPartElement  = $this->componentPartsById[$componentPartId];
		$componentPartSelector = $componentPartElement['selector'];
		$mergedSelector        = sprintf( '%s %s', $this->rootSelector, $componentPartSelector );
		$statesById            = Constants::getStatesById();
		$state                 = $rule->getState();
		if ( $state !== Constants::STATE_NORMAL ) {
			$mergedSelector = trim( $mergedSelector );
			$mergedSelector = sprintf( '%s%s', $mergedSelector, $statesById[ $state ]['selector'] );
		}
		$media     = $rule->getMedia();
		$mediaById = Constants::getMediaById();
		if ( $media !== Constants::MEDIA_DESKTOP ) {
			$mergedSelector = sprintf( '%s { %s ', $mediaById[ $media ]['query'], $mergedSelector );
		}

		return $mergedSelector;
	}

	public function generateRuleStyle( $rule ) {
		$selector = $this->getComponentPartselector( $rule );
		ob_start();
		?>
		<style type="text/css">
			<?php
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo $selector;
			?>
			{
			<?php
			foreach ( $rule->getStyle() as $property => $value ) {
				echo esc_html( sprintf( '%s: %s;', $property, $value ) );
			}

				//media query closing tag
			if ( $rule->getMedia() !== 'desktop' ) {
				echo '}';
			}
			?>
			}
		</style>
		<?php
		return  trim( strip_tags( ob_get_clean() ) );
	}

}
