<?php


namespace Neve\Core;


use Neve\Core\Styles\Frontend;
use Neve\Core\Styles\Generator;
use Neve\Core\Styles\Gutenberg;
use Neve\Core\Settings\Mods;
use Neve\Core\Settings\Config;

class Dynamic_Css {
	const FRONTEND_HANDLE = 'neve-style';
	const GUTENBERG_HANDLE = 'neve-gutenberg-style';
	/**
	 * Generator object.
	 *
	 * @var Generator CSS generator object.
	 */
	private $generator = null;
	const EDITOR_ACTION = 'enqueue_block_editor_assets';
	const FRONTEND_ACTION = 'wp_enqueue_scripts';

	/**
	 * Register actions.
	 */
	public function init() {
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue' ), 100 );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ), 100 );
		add_action( 'customize_controls_enqueue_scripts', [ $this, 'add_customize_vars_tag' ] );

		if ( is_customize_preview() ) {
			add_action( 'wp_head', [ $this, 'add_customize_vars_tag' ] );
		}
	}

	public function legacy_style() {
		$classes = apply_filters( 'neve_filter_inline_style_classes', [], 'neve-generated-style' );
		$mobile_css = '';
		$desktop_css = '';
		$tablet_css = '';
		foreach ( $classes as $class ) {
			if ( ! class_exists( $class ) ) {
				continue;
			}

			$object = new $class();
			$object->init();
			$mobile_css .= $object->get_style( 'mobile' );
			$desktop_css .= $object->get_style( 'desktop' );
			$tablet_css .= $object->get_style( 'tablet' );
		}
		$all_css = $mobile_css;
		if ( ! empty( $tablet_css ) ) {
			$all_css .= sprintf( '@media(min-width: 576px){ %s }', $tablet_css );
		}
		if ( ! empty( $desktop_css ) ) {
			$all_css .= sprintf( '@media(min-width: 960px){ %s }', $desktop_css );
		}
		add_filter( 'neve_dynamic_style_output', function ( $css ) use ( $all_css ) {
			return $all_css . $css;
		} );
	}

	/**
	 * Load frontend style.
	 */
	public function enqueue() {
		$is_for_gutenberg = (current_action() === self::EDITOR_ACTION);
		if ( ! class_exists( ' Neve_Pro\Core\Generic_Style', true ) ) {
			$this->legacy_style();
		}

		$generator_class = $is_for_gutenberg ? Gutenberg::class : Frontend::class;
		$generated_css = '';

		if ( class_exists( $generator_class ) ) {
			$this->generator = new $generator_class();
			$_subscribers = $this->generator->get();

			$_subscribers = array_merge( $_subscribers, apply_filters( 'neve_style_subscribers', [] ) );

			$this->generator->set( $_subscribers );

			$generated_css = $this->generator->generate();
		}

		$style = apply_filters( 'neve_dynamic_style_output', $generated_css, $is_for_gutenberg ? 'gutenberg' : 'frontend' );

		$style .= self::get_root_css();

		$style = self::minify_css( $style );

		wp_add_inline_style( $is_for_gutenberg ? self::GUTENBERG_HANDLE : self::FRONTEND_HANDLE, $style );
	}

	/**
	 * Basic CSS minification.
	 *
	 * @param string $css
	 *
	 * @return string
	 */
	public static function minify_css( $css ) {
		return preg_replace( '/\s+/', ' ', $css );
	}

	/**
	 * Adds customizer CSS tag for CSS vars.
	 */
	public function add_customize_vars_tag() {
		wp_register_style( 'nv-css-vars', false );
		wp_enqueue_style( 'nv-css-vars' );

		$css = ':root{' . $this->get_css_vars() . '}';
		$css .= apply_filters( 'neve_after_css_root', $css );
		wp_add_inline_style( 'nv-css-vars', self::minify_css($css ) );

		/**
		 * Custom colors needs a separate style to prevent overwriting the main color for the pallets.
		 */
		wp_register_style( 'nv-custom-color-vars', false );
		wp_enqueue_style( 'nv-custom-color-vars' );
		$custom_colors = self::get_global_custom_colors();
		$colors_css = '';
		foreach ( $custom_colors as $slug => $color ) {
			$colors_css .= '--' . $slug . ':' . $color . ';';
		}
		$css = ':root{' . esc_html( $colors_css ) . '}';
		wp_add_inline_style( 'nv-custom-color-vars', self::minify_css($css ) );
	}

	/**
	 * Get root style (css variables)
	 *
	 * @return string
	 */
	public static function get_root_css() {
		$css = ':root{';

		$css .= self::get_css_vars();
		$css .= self::get_fallback_font();

		/**
		 * We already have the style in customizer from add_customize_vars_tag method, no need to add it again.
		 * We do need it on frontend.
		 */
		if ( ! is_customize_preview() ) {
			$custom_colors = self::get_global_custom_colors();
			foreach ($custom_colors as $slug => $color) {
				$css .= '--' . $slug . ':' . $color . ';';
			}
		}

		$css .= '}';

		$css .= apply_filters( 'neve_after_css_root', $css );

		return self::minify_css( $css );
	}

	/**
	 * Get the fallback font.
	 *
	 * @return string
	 */
	public static function get_fallback_font() {
		$fallback = get_theme_mod( 'neve_fallback_font_family', 'Arial, Helvetica, sans-serif' );

		return '--nv-fallback-ff:' . $fallback . ';';
	}

	/**
	 * Get color values of the custom global colors
	 *
	 * @return string[] colors values HEX, RGB etc.
	 */
	private static function get_global_custom_colors() {
		$colors = [];

		foreach( Mods::get( Config::MODS_GLOBAL_CUSTOM_COLORS, [] ) as $slug=>$args ) {
			$colors[$slug] = $args['val'];
		}

		return $colors;
	}

	/**
	 * Returns CSS vars style.
	 *
	 * @return string
	 */
	private static function get_css_vars() {
		$global_colors = get_theme_mod( 'neve_global_colors', neve_get_global_colors_default( true ) );

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

		if ( ! isset( $global_colors[ 'activePalette' ] ) ) {
			return '';
		}

		$active = $global_colors[ 'activePalette' ];

		if ( ! isset( $global_colors[ 'palettes' ][ $active ] ) ) {
			return '';
		}

		$palette = $global_colors[ 'palettes' ][ $active ];

		if ( ! isset( $palette[ 'colors' ] ) ) {
			return '';
		}

		$css = '';

		foreach ( $palette[ 'colors' ] as $slug => $color ) {
			$css .= '--' . $slug . ':' . $color . ';';
		}

		return $css;
	}
}
