<?php


namespace Hecate\Components;


use Hecate\Controls\Components\ControlsRepository;
use Hecate\Icon;
use Hecate\Lodash;
use Hecate\Components\ComponentMods;
use Hecate\Style\StyleParser;

abstract class ComponentBase {

	protected $componentId               = null;
	public static $type                  = '';
	protected $panel                     = null;
	protected static $rootClass          = null;
	public $componentParts               = null;
	public $componentDefaults            = null;
	protected static $template           = null;
	protected static $oldActiveComponent = null;
	public $settingsApi                  = null;
	public $renderFromCustomizer         = false;
	public $renderFromFrontend           = false;




	public function __construct( $data = array() ) {
		$defaultData = array(
			'componentId' => null,
			'panel'       => null,
		);

		$mergedOptions           = Lodash::merge( array(), $defaultData, $data );
		$componentId             = $mergedOptions['componentId'];
		$panel                   = $mergedOptions['panel'];
		$this->componentId       = $componentId;
		$this->panel             = $panel;
		$this->componentParts    = $this->getComponentParts();
		$this->componentDefaults = $this->getComponentDefaults();

	}


	/**
	 * @return string|null gets the current objects(looks at the descendants class) namespace. We use the current namespace
	 * to autload some files, like the ui classes for content and style tabs controls, or the componentPart class
	 */
	public function getCurrentNamespace() {
		try {
			$currentClassName = get_class( $this );
			$reflector        = new \ReflectionClass( $currentClassName );
			$currentNamespace = $reflector->getNamespaceName();
			return $currentNamespace;
		} catch ( \Exception $e ) {
			return null;
		}
	}





	/**
	 * @return string|null returns dynamically the class of the componentParts used for the current component
	 */
	public function getComponentPartsClass() {
		$currentNamespace    = $this->getCurrentNamespace();
		$componentPartsClass = strtr(
			':currentNamespace\\ComponentParts',
			array(
				':currentNamespace' => $currentNamespace,
			)
		);
		if ( class_exists( $componentPartsClass ) ) {
			return $componentPartsClass;
		}

		return null;
	}

	public function getComponentParts() {
		$componentPartClass = $this->getComponentPartsClass();
		if ( class_exists( $componentPartClass ) ) {
			$componentPartObj = new $componentPartClass();
			$componentParts   = $componentPartObj->elements();
			return $componentParts;
		} else {
			return array();
		}
	}

	public function getComponentDefaultsClass() {
		$currentNamespace       = $this->getCurrentNamespace();
		$componentDefaultsClass = strtr(
			':currentNamespace\\Defaults',
			array(
				':currentNamespace' => $currentNamespace,
			)
		);
		if ( class_exists( $componentDefaultsClass ) ) {
			return $componentDefaultsClass;
		}

		return null;
	}

	public function getComponentDefaults() {
		$componentDefaultsClass = $this->getComponentDefaultsClass();
		if ( class_exists( $componentDefaultsClass ) ) {
			$defaultsObj       = new $componentDefaultsClass();
			$componentDefaults = $defaultsObj->get();
			return $componentDefaults;
		} else {
			return array();
		}
	}



	public function getSelector() {
		return '#hecate .' . $this->getComponentIdClass();
	}

	public function getSections() {
		return array();
	}

	public function getExtraRootClasses() {
		return array();
	}

	public function getComponentIdClass() {
		$componentId = $this->componentId;
		return "style-$componentId";
	}

	public function getRootClasses() {
		$extraRootClasses = $this->getExtraRootClasses();
		$classesArray     = array_merge(
			$extraRootClasses,
			array( 'hecate-component', static::$rootClass, $this->getComponentIdClass() )
		);
		return implode( ' ', $classesArray );
	}

	public function getSectionId() {
		return  $this->getComponentId();
	}

	public function settingPath( $setting ) {
		return $this->getComponentId() . '.' . $setting;
	}

	public function getComponentId() {

		return $this->componentId;
	}

	public function getCurrentPanel() {
			return $this->panel;
	}

	public function getInternalControls() {
		$controlClasses = ControlsRepository::getControlClasses();

		//because we don't set a tab and accordion the control wil lbe hidden
		$internalControls = array(
			array(
				'settingId' => 'component',
				'type'      => 'hecate-input',
			),
			array(
				'settingId' => 'data',
				'type'      => 'hecate-data-control',
			),
			array(
				'settingId' => 'children',
				'type'      => 'hecate-children',
			),
		);
		$output           = array();
		foreach ( $internalControls as $controlData ) {
			$type                 = Lodash::get( $controlData, 'type' );
			$controlClass         = Lodash::get( $controlClasses, $type, ControlsRepository::$defaultControl );
			$componentTypeControl = new $controlClass( $controlData, $this );
			$output[]             = $componentTypeControl;
		}
		return $output;
	}

	public function getControls() {
		return $this->getInternalControls();
	}



	//Rename to getComponentMod
	public function getData( $path, $defaultValue = null, $useComponentId = true ) {
		if ( $useComponentId ) {
			$path = $this->settingPath( $path );
		}

		$data = ComponentMods::getData( $path, $defaultValue );
		return $data;
	}

	public function getAttribute( $path, $defaultValue = null, $options = array() ) {
		//    $this->settingsApi->resetData();
		return $this->settingsApi->getAttribute( $path, $defaultValue, $options = array() );
	}

	public function getDesign( $path, $defaultValue = null, $options = array() ) {
		return $this->settingsApi->getDesign( $path, $defaultValue, $options );
	}

	public function getPartialRefreshSelector() {
		return sprintf( '[data-partial-refresh-setting="%s"]', $this->getComponentId() );
	}

	public function getCssSettings() {

		return $this->getDesign( 'componentPart', array(), array( 'componentPart' => null ) );
	}

	public function getCss() {

		$cssSettings = $this->getCssSettings();
		if ( is_array( $cssSettings ) && empty( $cssSettings ) ) {
			return '';
		}
		$params = array(
			'settings'       => $this->getCssSettings(),
			'componentParts' => $this->componentParts,
			'rootSelector'   => static::getSelector(),
		);
		$data   = StyleParser::getInstance()->parseSettingsToCss( $params );
		return $data;
	}

	public function renderCSS() {
		?>
	  <style type="text/css">
		<?php
              // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			  echo $this->getCss();
		?>
	  </style>
		<?php
	}

	public function rightPencil() {
		return false;
	}

	public function renderChildren() {
		$componentId = $this->componentId;
		$childrenIds = ComponentMods::getChildrenIds( $componentId );
		foreach ( $childrenIds as $childId ) {
			$componentType = ComponentMods::getComponentName( $childId );
			ComponentsRepository::render( $childId, $componentType );
		}
	}

	public function getExtraWrapperClasses() {
		return array();
	}

	public function getWrapperClass() {
		$rootClass = static::$rootClass;
		$classes   = array( "{$rootClass}__wrapper" );

		$classes = array_merge( $classes, $this->getExtraWrapperClasses() );

		return implode( ' ', $classes );
	}

	public function renderPartialRefreshContainer() {
		$this->renderFromCustomizer = true;
		$this->loadSettingsApi();
		$classes = array( 'position-relative', 'hecate-component', 'hecate-component--with-overlay', $this->getWrapperClass() );

		if ( $this->rightPencil() ) {
			$classes[] = 'customize-partial-edit-shortcut__right';
		}

		?>
	  <div data-partial-refresh-setting="<?php echo esc_attr( $this->getComponentId() ); ?>"
		   data-container-id="<?php echo esc_attr( $this->getSectionId() ); ?>"
	   data-component-type="<?php echo esc_attr( static::$type ); ?>"
		   class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>">
		  <?php $this->renderOverlay(); ?>
		  <?php $this->renderCSS(); ?>
		  <?php $this->renderTemplate(); ?>
	  </div>
		<?php
	}

	public function getOverlayClasses() {
		return array();
	}

	public function renderOverlay() {
		$overlayClasses       = $this->getOverlayClasses();
		$overlayClassesString = implode( ' ', $overlayClasses )
		?>
	  <div class="hecate-component-overlay <?php echo esc_attr( $overlayClassesString ); ?>">
	  <div class="hecate-component-overlay__pencil">
		<?php
      // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo Icon::get( 'font-awesome/pencil-alt' );
		?>
	  </div>
	  </div>
		<?php
	}

	public function renderTemplate() {
		$this->loadTemplatePart();
	}

	public function loadTemplatePart() {
		get_template_part( 'template-parts/' . static::$template );
	}

	public function beforeRender() {
	}

	public function afterRender() {
	}

	/**
	 * This function is not called in the constructor to handle the partial refresh. If this was loaded in consdtructor
	 * then the data would have been old
	 */
	public function loadSettingsApi() {
		$this->settingsApi = new SettingsApi( $this );
	}

	public function getPartialRefreshContent() {

		static::$oldActiveComponent = ComponentsRepository::getActiveComponent();

		ComponentsRepository::setActiveComponent( $this );

		ob_start();
		$this->renderPartialRefreshContainer();
		$data = ob_get_clean();

		ComponentsRepository::setActiveComponent( static::$oldActiveComponent );
		return $data;
	}

	public function renderFrontEnd() {
		$this->renderFromFrontend = true;
		$this->loadSettingsApi();
		$this->renderCSS();
		$this->renderTemplate();
	}

	public function renderCustomizer() {
		$this->renderPartialRefreshContainer();
	}

	public function render() {
		static::$oldActiveComponent = ComponentsRepository::getActiveComponent();
		ComponentsRepository::setActiveComponent( $this );
		$this->beforeRender();
		if ( is_customize_preview() ) {
			$this->renderCustomizer();
		} else {
			$this->renderFrontEnd();
		}
		$this->afterRender();

		ComponentsRepository::setActiveComponent( static::$oldActiveComponent );
	}


	public function isEnabled() {
		return true;
	}
}
