<?php
declare( strict_types=1 );

namespace FiboFilters\Integrations\Themes;

use FiboFilters\Config\AssetsLoader;
use FiboFilters\Config\Env;
use FiboFilters\Filtering\Front;
use FiboFilters\Settings\Settings;
use FiboFilters\WP\Helper as WPHelper;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class AbstractTheme
 *
 * @abstract
 */
abstract class AbstractTheme {
	/** @var string */
	protected $slug = '';
	/** @var string */
	protected $name = '';
	/** @var string */
	protected $docs_url = '';
	/** @var string */
	protected $theme_image = '';
	/** @var array */
	protected $args = [];

	/** @var WPHelper */
	protected $wp_helper;

	/** @var Front */
	protected $front;

	/** @var Settings */
	protected $settings;

	/** @var AssetsLoader */
	protected $assets_loader;

	public function __construct( WPHelper $wp_helper, Front $front, Settings $settings, AssetsLoader $assets_loader ) {
		$this->wp_helper     = $wp_helper;
		$this->front         = $front;
		$this->settings      = $settings;
		$this->assets_loader = $assets_loader;
	}

	/**
	 * Start method of every theme integration.
	 *
	 * @param string $slug Theme slug.
	 * @param string $name Theme name.
	 * @param array  $args Integration args.
	 */
	public function init( string $slug = '', string $name = '', array $args = [] ): void {
		$this->slug = $slug;
		$this->name = $name;
		$this->args = $args;

		if ( empty( $this->name ) || empty( $this->slug ) ) {
			return;
		}

		$this->args = $this->parse_args(
			wp_parse_args(
				$args,
				[
					'always_enabled'    => false,
					'white_label'       => false,
					'main_breakpoint'   => 0,
					'mobile_breakpoint' => 0,
					'docs_url'          => '',
					'theme_image'       => '',
					'overwritten'       => [],
					'integration_scope' => [],
					'sidebar_guide'     => [],
				]
			)
		);

		if ( ! empty( $this->args['docs_url'] ) ) {
			$this->docs_url = esc_url( $this->args['docs_url'] );
		}

		if ( ! empty( $this->args['theme_image'] ) ) {
			$this->theme_image = esc_url( $this->args['theme_image'] );
		}

		$this->add_settings_section();
		$this->add_settings_fields();

		$this->maybe_integrate();

		if ( is_admin() ) {
			$this->maybe_add_integration_scope_description();
			$this->maybe_display_sidebar_guide();
		}
	}

	/**
	 * It will turn on the theme integration if user enable it in the plugin settings.
	 */
	private function maybe_integrate(): void {

		if ( $this->is_integration_enabled() ) {
			$this->integrate_from_args();
			$this->integrate();
			$this->load_partial( $this->get_partial_filename() );
			if ( is_admin() ) {
				$this->maybe_mark_options_as_overridden();
			}

			// Sharing the details of the theme so that they can be checked, e.g. in other integrations (including Elementor).
			add_filter(
				'fibofilters/integrations/themes/active_integration',
				function () {
					return [
						'name' => $this->name,
						'slug' => $this->slug,
						'args' => [
							'overwritten'       => $this->args['overwritten'],
							'integration_scope' => $this->args['integration_scope'],
						],
					];
				}
			);
		}
	}

	/**
	 * Allowing to parse args in integration
	 *
	 * @param array $args Args.
	 */
	protected function parse_args( array $args ): array {
		return $args;
	}

	/**
	 * Check if the integration with the current theme is enabled.
	 */
	protected function is_integration_enabled(): bool {
		$enabled = get_option( 'fibofilters_general_enable_theme_integration_' . $this->slug );

		return (bool) $enabled;
	}

	/**
	 * Operations that should be fired when the integration is enabled.
	 * This method should be implemented in an inherited class.
	 */
	protected function integrate(): void {
	}

	/**
	 * Override common things directly from the arguments of {@link \FiboFilters\Integrations\Themes::get_supported_themes()}
	 */
	private function integrate_from_args(): void {

		if ( is_int( $this->args['main_breakpoint'] ) && $this->args['main_breakpoint'] > 0 ) {
			add_filter(
				'fibofilters/config/main_breakpoint',
				function (): int {
					return $this->args['main_breakpoint'];
				}
			);
		}

		if ( is_int( $this->args['mobile_breakpoint'] ) && $this->args['mobile_breakpoint'] > 0 ) {
			add_filter(
				'fibofilters/config/mobile_breakpoint',
				function (): int {
					return $this->args['mobile_breakpoint'];
				}
			);
		}

		if ( isset( $this->args['show_more_as_button'] ) && $this->args['show_more_as_button'] ) {
			add_filter( 'fibofilters/config/show_more_as_button', '__return_true' );
		}
	}

	/**
	 * Load dedicated partial assigned to the theme integration.
	 *
	 * @param string $partial_filename Partial filename.
	 */
	protected function load_partial( string $partial_filename = '' ): void {
		$partial_path = Env::$path . '/partials/integrations/themes/' . $partial_filename;

		if ( file_exists( $partial_path ) ) {
			require_once $partial_path;
		}
	}

	/**
	 * Get the filename of the partial assigned to the theme integration.
	 */
	protected function get_partial_filename(): string {
		return ! empty( $this->args['partial_filename'] ) ? $this->args['partial_filename'] : $this->slug . '.php';
	}

	/**
	 * Allow use \FiboFilters\Filtering\Front::config in partials.
	 *
	 * WARNING!
	 * This method could be fired in partials, but it has to be fired later than 'template_redirect' with priority 5.
	 *
	 * @param string $key Key.
	 * @param mixed  $default_value Default value.
	 *
	 * @return mixed
	 */
	public function get_config_value( string $key, $default_value = null ) {
		return $this->front->get_config_value( $key, $default_value );
	}

	/**
	 * Enqueue inline script
	 *
	 * @param string     $js JavaScript code.
	 * @param array      $deps Dependencies.
	 * @param string     $handle_suffix Handle suffix.
	 * @param bool|array $args Arguments.
	 * @param int        $priority Priority.
	 */
	public function enqueue_inline_script( string $js, array $deps = [], string $handle_suffix = '', $args = true, int $priority = 15 ) {
		$this->assets_loader->enqueue_inline_script( $js, $deps, $handle_suffix, $args, $priority );
	}

	/**
	 * Predefined descriptions used in theme integration.
	 *
	 * @param string $key Description key.
	 */
	protected function get_settings_description( string $key ): string {
		$desc = '';
		switch ( $key ) {
			case 'color_replacement':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( '%s theme-specific <b>color palette</b> will be used.', '[admin]', 'fibofilters' ), $this->name );
				break;
			case 'breakpoints':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( '%s theme-specific <b><i>breakpoints</i></b> will be used.', '[admin]', 'fibofilters' ), $this->name );
				break;
			case 'off_canvas_position':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( '%s theme-specific <b><i>off-canvas</i></b> position will be used.', '[admin]', 'fibofilters' ), $this->name );
				break;
			case 'mobile_toolbar':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( 'Support %s theme-specific <b><i>mobile toolbar</i></b>.', '[admin]', 'fibofilters' ), $this->name );
				break;
			case 'css':
				$desc = _x( 'Complementary CSS styles will be added.', '[admin]', 'fibofilters' );
				break;
			case 'overridden':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( 'This option is overwritten by the <b>%s</b> theme integration.', '[admin]', 'fibofilters' ), $this->name );
				break;
			case 'products_per_page':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( '%s theme-specific <b><i>products per page</i></b> will be used.', '[admin]', 'fibofilters' ), $this->name );
				break;
			case 'pagination_strategy':
				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( '%s theme-specific <b><i>pagination strategy</i></b> will be used.', '[admin]', 'fibofilters' ), $this->name );
				break;
		}

		return $desc;
	}

	/**
	 * Inject a default setting fields of the theme integration to the general view
	 */
	protected function add_settings_fields(): void {
		add_filter(
			'fibofilters/settings/section=general',
			function ( array $settings ): array {
				$settings[55] = [
					'name'      => 'enable_theme_integration_' . $this->slug,
					'type'      => 'toggle',
					'label'     => _x( 'Enable integration', '[admin]', 'fibofilters' ),
					'className' => 'fibofilters-settings-no-bottom-gap',
					'default'   => false,
					'schema'    => [
						'type' => 'boolean',
					],
					'group'     => 'theme_integration',
				];

				return $settings;
			}
		);
	}

	/**
	 * Mark selected options as overridden
	 */
	protected function maybe_mark_options_as_overridden(): void {
		if ( isset( $this->args['overridden'] ) && ! empty( $this->args['overridden'] ) ) {
			foreach ( $this->args['overridden'] as $section => $fields ) {
				add_filter(
					'fibofilters/settings/section=' . $section,
					function ( array $settings ) use ( $fields ): array {
						if ( empty( $fields ) ) {
							return $settings;
						}

						foreach ( $fields as $field ) {
							$filtered = wp_list_filter( $settings, [ 'name' => $field ] );
							if ( empty( $filtered ) ) {
								continue;
							}
							$key = array_keys( $filtered )[0];
							if ( intval( array_keys( $filtered )[0] ) <= 0 ) {
								continue;
							}

							$settings[ $key ]['override'] = [
								'description' => $this->get_settings_description( 'overridden' ),
							];
						}

						return $settings;
					},
					20
				);
			}
		}
	}

	protected function maybe_add_integration_scope_description(): void {
		if ( empty( $this->args['integration_scope'] ) || ! is_array( $this->args['integration_scope'] ) ) {
			return;
		}

		$scope = $this->args['integration_scope'];

		add_filter(
			'fibofilters/settings/section=general',
			function ( array $settings ) use ( $scope ): array {
				// Enable integration description.
				$settings[55]['description'] = _x( 'What happens when you activate the integration?', '[admin]', 'fibofilters' );

				// Enable integration description - extra HTML.
				$html = '<ol>';
				foreach ( $scope as $item ) {
					$text = $this->get_settings_description( $item );
					if ( ! empty( $text ) ) {
						$html .= '<li>' . $text . '</li>';
					}
				}
				$html .= '</ol>';

				$settings[56] = [
					'name'  => 'enable_theme_integration_html',
					'type'  => 'html',
					'html'  => $html,
					'group' => 'theme_integration',
				];

				return $settings;
			},
			15
		);
	}

	/**
	 * Display extra information how to add filters to a sidebar in specific theme.
	 */
	protected function maybe_display_sidebar_guide(): void {
		if ( empty( $this->args['sidebar_guide'] ) || ! is_array( $this->args['sidebar_guide'] ) ) {
			return;
		}
		$conditions = $this->args['sidebar_guide'];

		add_filter(
			'fibofilters/settings/section=general',
			function ( array $settings ) use ( $conditions ): array {

				$added             = false;
				$html              = '';
				$widget_area_id    = $conditions['widget_area_id'];
				$widget_area_label = $conditions['widget_area_label'];

				if ( $conditions['widgets_type'] === 'classic' ) {
					$ff_widget_id = 'fibofilters-filters-widget';
					$added        = $this->wp_helper->is_widget_in_widget_area( $ff_widget_id, $widget_area_id );
				}

				if ( $conditions['widgets_type'] === 'blocks' ) {
					foreach ( $this->wp_helper->get_widget_areas_containing_ff_elements() as $key => $widget_area ) {
						if ( $key === $widget_area_id ) {
							$added = true;
							break;
						}
					}
				}

				if ( $added ) {
					$html .= '<p class="fibofilters-settings-location-sidebar-ok">';
					$html .= '<span class="dashicons dashicons-yes-alt"></span>';
					$html .= '<span>';
					/* translators: %s: name of the sidebar */
					$html .= sprintf( _x( '<b>Well done!</b> Filters have been successfully added as a WordPress widget under the widget area called “<b>%s</b>”.', '[admin]', 'fibofilters' ), $widget_area_label );
					$html .= '</span>';
					$html .= '</p>';
				} else {
					$extra_steps = apply_filters( 'fibofilters/integrations/themes/extra_guide_steps', [], $this->slug );
					/* translators: %s: name of the theme */
					$html .= '<p>' . sprintf( _x( 'To display FiboFilters in the %s theme sidebar, follow these steps:', '[admin]', 'fibofilters' ), $this->name ) . '</p>';
					$html .= '<ol>';
					foreach ( $extra_steps as $step ) {
						$html .= '<li>' . $step . '</li>';
					}

					/* translators: %s: URL address to the WordPress widgets view */
					$html .= '<li>' . sprintf( _x( 'Go to <code><a href="%s" target="_blank">Appearance -> Widgets</a></code>.', '[admin]', 'fibofilters' ), $this->get_widgets_link() ) . '</li>';

					if ( $conditions['widgets_type'] === 'classic' ) {
						$html .= '<li>' . sprintf( _x( 'Add widget called “<b>FiboFilters - product filters</b>” to the widget area called “<b>%s</b>”.', '[admin]', 'fibofilters' ), $widget_area_label ) . '</li>';
					}

					if ( $conditions['widgets_type'] === 'blocks' ) {
						$html .= '<li>' . sprintf( _x( 'Add a block called <b>FiboFilters</b> to the widget area called “<b>%s</b>” and click Update.', '[admin]', 'fibofilters' ), $widget_area_label ) . '</li>';
					}

					$html .= '</ol>';

					if ( ! empty( $this->docs_url ) ) {
						$html .= '<p>';
						/* translators: %s: 1: name of the theme, 2: url to the documentation  */
						$html .= sprintf( _x( 'More details on how to add filters to the sidebar in the <b>%1$s</b> theme can be found in <a href="%2$s" target="_blank" >our documentation</a>.', '[admin]', 'fibofilters' ), $this->name, $this->docs_url );
						$html .= '</p>';
					}
				}

				$sidebar_doc = Env::$doc_url . 'get-started/filter-location-sidebar/';
				$html       .= '<p>';
				/* translators: 1: Plugin documentation URL */
				$html .= sprintf( _x( 'Learn more about <a href="%s" target="_blank">displaying filters in a sidebar</a>.', '[admin]', 'fibofilters' ), $sidebar_doc );
				$html .= '</p>';

				$settings[260]['html'] = $html;

				return $settings;
			},
			15
		);
	}

	/**
	 * Inject a default setting section of the theme integration to the general view
	 */
	protected function add_settings_section(): void {
		add_filter(
			'fibofilters/settings/section=general',
			function ( array $settings ): array {

				/* translators: %s: Name of WordPress theme */
				$headline = sprintf( _x( 'Seamless integration with %s', '[admin]', 'fibofilters' ), '<b>' . $this->name . '</b>' );

				/* translators: %s: Name of WordPress theme */
				$desc = sprintf( _x( "You're using the %s theme. Fantastic! We’ve made a dedicated integration with your theme.", '[admin]', 'fibofilters' ), '<b>' . $this->name . '</b>' );

				if ( ! empty( $this->docs_url ) ) {
					$desc .= ' ' . sprintf( '<a href="%s" target="_blank" >' . _x( 'Learn more', '[admin]', 'fibofilters' ) . '</a>.', $this->docs_url );
				}

				if ( ! empty( $this->theme_image ) ) {
					/* translators: %s: URL to the documentation */
					$desc .= '<img class="fibofilters-settings-theme-image" src="' . $this->theme_image . '" />';
				}

				$settings[50] = [
					'name'        => 'theme_integration_header',
					'type'        => 'header',
					'label'       => $headline,
					'description' => $desc,
					'group'       => 'theme_integration',
				];

				return $settings;
			}
		);
	}

	/**
	 * Get link to the WordPress widgets view.
	 */
	protected function get_widgets_link(): string {
		return esc_url( admin_url( 'widgets.php' ) );
	}
}
