<?php

namespace Hecate\Style;

use Hecate\Lodash;
use Hecate\Style\Parsers\Background;
use Hecate\Style\Parsers\Border;
use Hecate\Style\Parsers\CustomMinHeight;
use Hecate\Style\Parsers\CustomWidth;
use Hecate\Style\Parsers\General;
use Hecate\Style\Parsers\Margin;
use Hecate\Style\Parsers\Padding;
use Hecate\Style\Parsers\Typography;


class StyleParser {


	private static $instance = null;
	private $parsers         = array();

	private function __construct() {
		$this->loadParsers();
	}

	public static function getInstance() {
		if ( self::$instance === null ) {
			self::$instance = new static();
		}

		return self::$instance;
	}

	public function getParsers() {
		return array(
			'background'      => Background::class,
			'general'         => General::class,
			'typography'      => Typography::class,
			'padding'         => Padding::class,
			'margin'          => Margin::class,
			'border'          => Border::class,
			'customMinHeight' => CustomMinHeight::class,
			'customWidth'     => CustomWidth::class,
		);
	}

	public function getData( $path, $default = '' ) {
		return get_theme_mod( $path, $default );
	}

	public function parseSettingsToCss( $data ) {
		$data                        = Lodash::merge(
			array(
				'settings'       => array(),
				'componentParts' => null,
				'rootSelector'   => '',
			),
			$data
		);
		$styleGroupedByComponentPart = $data['settings'];
		$componentParts              = $data['componentParts'];
		$rootSelector                = $data['rootSelector'];
		$rulesManager                = new RulesManager( $rootSelector, $componentParts );

		$this->generateRules( $styleGroupedByComponentPart, $componentParts, $rulesManager );
		$css = $rulesManager->generateCSS();
		return $css;
	}


	public function generateRules( $styleGroupedByComponentPart, $componentParts, $rulesManager ) {
		$componentPartsById = Lodash::keyBy( $componentParts, 'id' );
		foreach ( $styleGroupedByComponentPart as $componentPartId => $componentPartData ) {
			$componentPart = $componentPartsById[ $componentPartId ];
			$stateData     = Lodash::get( $componentPartData, 'state', array() );
			$mediaData     = Lodash::get( $componentPartData, 'media', array() );
			Lodash::unsetValue( $componentPartData, 'state' );
			Lodash::unsetValue( $componentPartData, 'media' );
			$this->addRules( $componentPartData, $componentPart, $rulesManager );

			foreach ( $stateData as $stateKey => $stateData ) {
				$options = array(
					'state' => $stateKey,
				);
				$this->addRules( $stateData, $componentPart, $rulesManager, $options );
			}
			foreach ( $mediaData as $mediaKey => $dataByMedia ) {
				$options = array(
					'media' => $mediaKey,
				);

				$stateDataByMedia = Lodash::get( $dataByMedia, 'state', array() );
				Lodash::unsetValue( $dataByMedia, 'state' );

				$this->addRules( $dataByMedia, $componentPart, $rulesManager, $options );

				foreach ( $stateDataByMedia as $stateKey => $stateData ) {
					$options = array(
						'media' => $mediaKey,
						'state' => $stateKey,
					);
					$this->addRules( $stateData, $componentPart, $rulesManager, $options );
				}
			}
		}
	}
	public function addRules( $data, $componentPart, $rulesManager, $options = array() ) {
		foreach ( $data as $parserName => $propertyValue ) {
			if ( ! isset( $this->parsers[ $parserName ] ) ) {
				continue;
			}
			$style = call_user_func( $this->parsers[ $parserName ] . '::parse', $propertyValue );
			$rulesManager->addRule( $style, $componentPart, $options );
		}
	}

	public function getPropertyFromSetting( $setting ) {
		$path      = $setting['path'];
		$pathParts = explode( '.', $path );
		$property  = $pathParts[0];
		array_shift( $pathParts );
		$parsers = $this->getParsers();
		//general style, not an object
		if ( count( $pathParts ) === 0 ) {
			if ( array_key_exists( $property, $parsers ) ) {
				return array(
					'parser' => $property,
					'path'   => '',
				);
			}
			return array(
				'parser' => 'general',
				'path'   => $property,
			);
		} else {
			$localPath = implode( '.', $pathParts );
			return array(
				'parser' => $property,
				'path'   => $localPath,
			);
		}

	}

	private function loadParsers() {
		$this->parsers = $this->getParsers();
	}


}
