<?php
/**
 * Seventhqueen\Typer\Customizer\Component class
 *
 * @package typer
 */

namespace Seventhqueen\Typer\Customizer;

use Seventhqueen\Typer\Component_Interface;
use function Seventhqueen\Typer\color_contrast;
use function Seventhqueen\Typer\hex_to_hsl;
use function Seventhqueen\Typer\typer;
use function add_action;
use function wp_enqueue_script;
use function get_theme_file_uri;

/**
 * Class for managing Customizer integration.
 */
class Component implements Component_Interface {

	private $helper;

	private $css_vars = [];

	/**
	 * List of auto-loaded modules.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	protected $modules = [
		'kirki-extend' => '\Seventhqueen\Typer\Customizer\Modules\Kirki_Extend\Module',
		'post-message' => '\Seventhqueen\Typer\Customizer\Modules\Post_Message\Module',
	];

	/**
	 * Gets the unique identifier for the theme component.
	 *
	 * @return string Component slug.
	 */
	public function get_slug() {
		return 'customizer';
	}

	/**
	 * Adds the action and filter hooks to integrate with WordPress.
	 */
	public function initialize() {

		$this->populate_settings();

		$this->kirki_only_actions();

		// Customizer preview.
		add_action( 'customize_preview_init', [ $this, 'action_enqueue_customize_preview_js' ], 12 );

		add_action( 'init', [ $this, 'populate_css_vars' ] );
		add_action( 'wp_head', [ $this, 'css_vars_style' ], 999 );
		add_action( 'admin_head', [ $this, 'css_vars_style' ], 999 );

		// Fallback & Recommend.
		add_action( 'customize_register', [ $this, 'customize_register' ], 999 );
		add_action( 'wp_ajax_kirki_installer_dismiss', [ $this, 'kirki_installer_dismiss' ] );
	}

	/**
	 * Actions run only when Kirki is active
	 */
	private function kirki_only_actions() {

		if ( ! class_exists( '\Kirki' ) ) {
			return;
		}

		add_filter( 'kirki_modules', [ $this, 'remove_css_vars' ] );
		add_action( 'customize_register', [ $this, 'register_control_types' ] );
		add_action( 'customize_controls_enqueue_scripts', [ $this, 'enqueue_controls_scripts' ] );
		add_filter( 'kirki_telemetry', '__return_false' );

		$this->load_modules();

	}

	/**
	 * Load modules.
	 *
	 * @since 1.0.0
	 */
	protected function load_modules() {

		foreach ( $this->modules as $module ) {
			if ( class_exists( $module ) && ( ! method_exists( $module, 'active' ) || $module::active() ) ) {
				new $module();
			}
		}
	}

	/**
	 * Register all control types.
	 *
	 * @param object $wp_customize Global customize object.
	 *
	 * @since 1.0.0
	 *
	 */
	public function register_control_types( $wp_customize ) {
		foreach ( Helper::$control_types as $control_type ) {
			$wp_customize->register_control_type( $control_type );
		}
	}


	/**
	 * Populates the $vars property of this object.
	 *
	 * @access public
	 * @return void
	 * @since 1.0.0
	 */
	public function populate_css_vars() {

		// Get an array of all fields.
		$fields = typer()->get_settings()['set'];

		foreach ( $fields as $id => $args ) {
			if ( ! isset( $args['css_vars'] ) || empty( $args['css_vars'] ) ) {
				continue;
			}
			$val = typer()->get_option( $id );
			foreach ( $args['css_vars'] as $css_var ) {

				$final_value = '';

				if ( isset( $css_var[2] ) && is_array( $val ) && isset( $val[ $css_var[2] ] ) ) {
					// input with px, em, %
					$val[ $css_var[2] ] = $this->concatenate_input_size_unit( $val[ $css_var[2] ] );
					$final_value        = str_replace( '$', $val[ $css_var[2] ], $css_var[1] );

				} else {
					if ( $val ) {
						// input with px, em, %
						$val = $this->concatenate_input_size_unit( $val );

						if ( isset( $css_var[1] ) ) {
							$final_value = str_replace( '$', $val, $css_var[1] );
							if ( strpos( $final_value, 'hex_to_hsl_' ) !== false ) {
								$final_value = str_replace( 'hex_to_hsl_', '', $final_value );
								$final_value = hex_to_hsl( $val, $final_value );
							}

							if ( strpos( $final_value, 'color_contrast' ) !== false ) {
								$final_value = color_contrast( $val );
							}

							if ( strpos( $final_value, 'color_contrast_hsl' ) !== false ) {
								$final_value = color_contrast( $val, true );
							}
						} else {
							$final_value = $val;
						}
					}
				}

				if ( $final_value !== '' ) {
					$this->css_vars[ $css_var[0] ] = $final_value;
				}
			}
		}
	}

	private function concatenate_input_size_unit( $val ) {
		if ( ! is_array( $val ) ) {
			return $val;
		}
		$initial = $val;

		if ( isset( $initial['size'] ) ) {

			if ( $initial['size'] == '' ) {
				return '';
			}

			$val = $initial['size'];

			if ( isset( $initial['unit'] ) ) {
				$val .= str_replace( '-', '', $initial['unit'] );
			}
		} elseif ( isset( $initial['unit'] ) ) {
			//extra fallback when size is not defined
			return '';
		}

		return $val;
	}

	/**
	 * Add styles in <head>.
	 *
	 * @access public
	 * @return void
	 * @since 1.0.0
	 */
	public function css_vars_style() {
		echo '<style id="typer-css-vars">';
		if ( ! empty( $this->css_vars ) ) {
			echo ':root{';
			foreach ( $this->css_vars as $var => $val ) {
				if ( ( $var === '--media-max-height' || $var === '--layout-max-width' ) && $val !== '' ) {
					if ( strpos( $val, 'px' ) === false ) {
						$val .= 'px';
					}
				}

				if ( $val !== '' ) {
					echo esc_html( $var ) . ':' . esc_html( $val ) . ';';
				}
			}
			echo '}';
		}
		echo '</style>';
	}

	/**
	 * Enqueues customizer scripts & styles
	 */
	public function enqueue_controls_scripts() {
		$css_uri  = Utils::get_assets_url() . '/css';
		$css_path = Utils::get_assets_path() . '/css';
		$js_uri   = Utils::get_assets_url() . '/js';
		$js_path  = Utils::get_assets_path() . '/js';

		wp_register_script( 'typer-stepper', $js_uri . '/stepper/stepper.js', [], '1.0.0', true );
		wp_register_script( 'typer-url-polyfill', $js_uri . '/url-polyfill/url-polyfill.js', [], '1.1.0', false );
		wp_register_script( 'typer-rangeslider', $js_uri . '/panel/rangeslider.min.js', [], '1.0.0', true );
		wp_register_script( 'typer-custom', $js_uri . '/panel/panel.js', [], '1.0.0', true );

		wp_enqueue_script(
			'typer-customizer-components',
			$js_uri . '/customizer-components.js',
			[
				'jquery',
				'jquery-ui-draggable',
				'jquery-ui-sortable',
				'typer-stepper',
				'typer-url-polyfill',
				'typer-rangeslider',
				'typer-custom'
			],
			typer()->get_asset_version( $js_path . '/customizer-components.js' ),
			true
		);

		wp_enqueue_style(
			'typer-customizer',
			$css_uri . '/customizer.css',
			[],
			typer()->get_asset_version( $css_path . '/customizer.css' ) );

	}

	/**
	 * Enqueues JavaScript to make Customizer preview reload changes asynchronously.
	 */
	public function action_enqueue_customize_preview_js() {

		wp_enqueue_script(
			'typer-customizer',
			get_theme_file_uri( '/assets/admin/js/customizer.js' ),
			[ 'customize-preview' ],
			typer()->get_asset_version( get_theme_file_path( '/assets/admin/js/customizer.js' ) ),
			true
		);

		$fields = typer()->get_settings()['set'];
		$data   = [];
		foreach ( $fields as $field_id => $field ) {
			if ( isset( $field['transport'] ) && isset( $field['css_vars'] ) && ! empty( $field['css_vars'] ) ) {
				$field['settings'] = $field_id;
				$data[]            = $field;
			}
		}

		wp_localize_script( 'typer-customizer', 'TyperCssVarFields', $data );
	}

	/**
	 *
	 */
	private function populate_settings() {
		$this->helper = Helper::instance();

		/**
		 * First of all, add the config.
		 *
		 * @link https://aristath.github.io/kirki/docs/getting-started/config.html
		 */
		Helper::add_config(
			'typer_options', [
				'capability'  => 'edit_theme_options',
				'option_type' => 'theme_mod',
				//'gutenberg_support' => true
			]
		);

		$all_options = typer()->get_settings();

		foreach ( $all_options['panels'] as $panel_id => $panel ) {

			if ( ! isset( $panel['description'] ) ) {
				$panel['description'] = '';
			}
			Helper::add_panel(
				$panel_id, $panel
			);
		}
		foreach ( $all_options['sec'] as $section_id => $section ) {

			if ( ! isset( $section['description'] ) ) {
				$section['description'] = '';
			}

			Helper::add_section( str_replace( '-', '_', $section_id ), $section );
		}

		foreach ( $all_options['set'] as $setting_id => $s ) {

			if ( isset( $s['type'] ) && $s['type'] == 'image_select' ) {
				$s['type']    = 'radio-image';
				$s['choices'] = [];
				foreach ( $s['options'] as $k => $option ) {
					$s['choices'][ $k ] = $option['img'];
				}
			}

			if ( isset( $s['id'] ) ) {
				$s['settings'] = $s['id'];
				unset( $s['id'] );
			} else {
				$s['settings'] = $setting_id;
			}

			if ( isset( $s['title'] ) ) {
				$s['label'] = $s['title'];
				unset( $s['title'] );
			}

			$this->add_field( $s );

		}

		add_filter( 'kirki_config', [ $this, 'kirki_styling' ] );
	}

	/**
	 * @param $config
	 *
	 * @return array
	 */
	function kirki_styling( $config ) {
		return wp_parse_args( [
			'disable_loader' => true,
		], $config );
	}

	/**
	 * @param $args
	 */
	public function add_field( $args ) {
		Helper::add_field( 'typer_options', $args );
	}

	/**
	 * Registers the section, setting & control for the kirki installer.
	 *
	 * @param object $wp_customize The main customizer object.
	 */
	public function customize_register( $wp_customize ) {

		if ( class_exists( 'Kirki' ) || ! class_exists( '\WP_Customize_Section' ) ) {
			return;
		}

		// Early exit if the user has dismissed the notice.
		if ( is_callable( [
				'\Seventhqueen\Typer\Customizer\Kirki_Installer_Section',
				'is_dismissed'
			] ) && Kirki_Installer_Section::is_dismissed() ) {
			return;
		}

		$wp_customize->add_section(
			new Kirki_Installer_Section(
				$wp_customize, 'kirki_installer', [
					'title'      => '',
					'capability' => 'install_plugins',
					'priority'   => 0,
				]
			)
		);
		$wp_customize->add_setting(
			'kirki_installer_setting', [
				'sanitize_callback' => '__return_true',
			]
		);
		$wp_customize->add_control(
			'kirki_installer_control', [
				'section'  => 'kirki_installer',
				'settings' => 'kirki_installer_setting',
			]
		);
	}

	/**
	 * Remove default CSS vars module from Kirki
	 *
	 * @param $modules
	 *
	 * @return mixed
	 */
	public function remove_css_vars( $modules ) {
		unset( $modules['css-vars'] );

		return $modules;
	}

	/**
	 * Allow to remove method for an hook when, it's a class method used and class don't have variable, but you know the class name :)
	 */
	function remove_filters_for_anonymous_class( $hook_name = '', $class_name = '', $method_name = '', $priority = 0 ) {
		global $wp_filter;
		// Take only filters on right hook name and priority
		if ( ! isset( $wp_filter[ $hook_name ][ $priority ] ) || ! is_array( $wp_filter[ $hook_name ][ $priority ] ) ) {
			return false;
		}
		// Loop on filters registered
		foreach ( (array) $wp_filter[ $hook_name ][ $priority ] as $unique_id => $filter_array ) {
			// Test if filter is an array ! (always for class/method)
			if ( isset( $filter_array['function'] ) && is_array( $filter_array['function'] ) ) {
				// Test if object is a class, class and method is equal to param !
				if ( is_object( $filter_array['function'][0] ) && get_class( $filter_array['function'][0] ) && get_class( $filter_array['function'][0] ) == $class_name && $filter_array['function'][1] == $method_name ) {
					// Test for WordPress >= 4.7 WP_Hook class (https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/)
					if ( is_a( $wp_filter[ $hook_name ], 'WP_Hook' ) ) {
						unset( $wp_filter[ $hook_name ]->callbacks[ $priority ][ $unique_id ] );
					} else {
						unset( $wp_filter[ $hook_name ][ $priority ][ $unique_id ] );
					}
				}
			}
		}

		return false;
	}


	/**
	 * Handles dismissing the plugin-install/activate recommendation.
	 * If the user clicks the "Don't show this again" button, save as user-meta.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function kirki_installer_dismiss() {
		check_ajax_referer( 'dismiss-kirki-recommendation', 'security' );
		$user_id = get_current_user_id();
		// @codingStandardsIgnoreLine WordPress.VIP.RestrictedFunctions.user_meta_update_user_meta
		if ( update_user_meta( $user_id, 'dismiss-kirki-recommendation', true ) ) {
			echo 'success! :-)';
			wp_die();
		}
		echo 'failed :-(';
		wp_die();
	}
}
