<?php
declare( strict_types=1 );

namespace FiboFilters\Config;

use FiboFilters\Blocks\Blocks;
use FiboFilters\Filters\FiltersDebugger;
use FiboFilters\Widgets\Widgets;
use FiboFilters\DI\ContainerWrapper;
use FiboFilters\Filtering\Request;
use FiboFilters\Indexer\Filters\Database;
use FiboFilters\Integrations\BulkIntegrations;
use FiboFilters\Integrations\Multilingual;
use FiboFilters\Integrations\Plugins;
use FiboFilters\Integrations\Themes;
use FiboFilters\Settings\Settings;
use FiboFilters\Shortcodes\FiboFilters as FiboFiltersShortcode;
use FiboFilters\Shortcodes\FiboFiltersAppliedFilters as FiboFiltersAppliedFiltersShortcode;
use FiboFilters\Shortcodes\FiboFiltersShowMoreProductsBtn as FiboFiltersShowMoreProductsBtnShortcode;
use FiboFilters\Shortcodes\FiboFiltersShowPreviousProductsBtn as FiboFiltersShowPreviousProductsBtnShortcode;
use FiboFilters\Shortcodes\FiboFiltersInfiniteScrollTrigger as FiboFiltersInfiniteScrollTriggerShortcode;
use FiboFilters\Shortcodes\FiboFiltersOrdering as FiboFiltersOrderingShortcode;
use FiboFilters\Shortcodes\FiboFiltersPagination as FiboFiltersPaginationShortcode;
use Freemius;

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

/**
 * Class Initializer
 */
class Initializer {

	/** @var Blocks */
	private $blocks;

	/** @var Widgets */
	private $widgets;

	/** @var ContainerWrapper */
	private $container;

	/** @var Database */
	private $database;

	/** @var FiboFiltersShortcode */
	private $fibofilters_shortcode;

	/** @var FiboFiltersAppliedFiltersShortcode */
	private $fibofilters_applied_filters_shortcode;

	/** @var FiboFiltersShowMoreProductsBtnShortcode */
	private $fibofilters_show_more_products_btn_shortcode;

	/** @var FiboFiltersShowPreviousProductsBtnShortcode */
	private $fibofilters_show_previous_products_btn_shortcode;

	/** @var FiboFiltersInfiniteScrollTriggerShortcode */
	private $fibofilters_infinite_scroll_trigger_shortcode;

	/** @var FiboFiltersOrderingShortcode */
	private $fibofilters_ordering_shortcode;

	/** @var FiboFiltersPaginationShortcode */
	private $fibofilters_pagination_shortcode;

	/** @var FiltersDebugger */
	private $filters_debugger;

	/** @var Freemius */
	private $freemius;

	/** @var FreemiusConfig */
	private $freemius_config;

	/** @var Index */
	private $index;

	/** @var IndexPusher */
	private $index_pusher;

	/** @var Multilingual */
	private $multilingual;

	/** @var Plugins */
	private $plugins;

	/** @var Request */
	private $request;

	/** @var Requirements */
	private $requirements;

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

	/** @var Themes */
	private $themes;

	/** @var BulkIntegrations */
	private $bulk_integrations;

	/** @var Troubleshooting */
	private $troubleshooting;

	public function __construct(
		Blocks $blocks,
		Widgets $widgets,
		ContainerWrapper $container,
		FiboFiltersShortcode $fibofilters_shortcode,
		FiboFiltersAppliedFiltersShortcode $fibofilters_applied_filters_shortcode,
		FiboFiltersShowMoreProductsBtnShortcode $fibofilters_show_more_products_btn_shortcode,
		FiboFiltersShowPreviousProductsBtnShortcode $fibofilters_show_previous_products_btn_shortcode,
		FiboFiltersInfiniteScrollTriggerShortcode $fibofilters_infinite_scroll_trigger_shortcode,
		FiboFiltersOrderingShortcode $fibofilters_ordering_shortcode,
		FiboFiltersPaginationShortcode $fibofilters_pagination_shortcode,
		Database $database,
		Freemius $freemius,
		FreemiusConfig $freemius_config,
		Index $index,
		IndexPusher $index_pusher,
		Multilingual $multilingual,
		Plugins $plugins,
		Request $request,
		Requirements $requirements,
		Settings $settings,
		Themes $themes,
		BulkIntegrations $bulk_integrations,
		Troubleshooting $troubleshooting,
		FiltersDebugger $filters_debugger
	) {
		$this->blocks                                       = $blocks;
		$this->widgets                                      = $widgets;
		$this->container                                    = $container;
		$this->fibofilters_shortcode                        = $fibofilters_shortcode;
		$this->fibofilters_applied_filters_shortcode        = $fibofilters_applied_filters_shortcode;
		$this->fibofilters_show_more_products_btn_shortcode = $fibofilters_show_more_products_btn_shortcode;
		$this->fibofilters_show_previous_products_btn_shortcode = $fibofilters_show_previous_products_btn_shortcode;
		$this->fibofilters_infinite_scroll_trigger_shortcode    = $fibofilters_infinite_scroll_trigger_shortcode;
		$this->fibofilters_ordering_shortcode                   = $fibofilters_ordering_shortcode;
		$this->fibofilters_pagination_shortcode                 = $fibofilters_pagination_shortcode;
		$this->database          = $database;
		$this->freemius          = $freemius;
		$this->freemius_config   = $freemius_config;
		$this->index             = $index;
		$this->index_pusher      = $index_pusher;
		$this->multilingual      = $multilingual;
		$this->plugins           = $plugins;
		$this->request           = $request;
		$this->requirements      = $requirements;
		$this->settings          = $settings;
		$this->themes            = $themes;
		$this->bulk_integrations = $bulk_integrations;
		$this->troubleshooting   = $troubleshooting;
		$this->filters_debugger  = $filters_debugger;
	}

	public function init(): void {
		// Load translations.
		add_action( 'init', [ $this, 'load_translations' ] );

		register_activation_hook( Env::$file, [ $this, 'run_activator' ] );

		add_action( 'plugins_loaded', [ $this, 'early_initialize' ], 5 );
		add_action( 'plugins_loaded', [ $this, 'initialize' ], 15 );
		add_action( 'plugins_loaded', [ $this, 'late_initialize' ], 100 );

		add_action( 'fibofilters/add_action', [ $this, 'add_action' ], 10, 4 );
		add_action( 'fibofilters/remove_action', [ $this, 'remove_action' ], 10, 4 );
	}

	public function run_activator(): void {
	}

	public function early_initialize() {
		$this->freemius_config->init();

		Env::set_plugin_full_name( 'FiboFilters' );
		if ( $this->freemius->is__premium_only() ) {
			Env::set_plugin_full_name( 'FiboFilters Pro' );
		}

		$this->plugins->early_init();
	}

	/**
	 * Initialize
	 */
	public function initialize(): void {
		if ( ! $this->requirements->check_all_requirements() ) {
			$this->requirements->show_errors_as_notices();

			return;
		}

		$this->settings->init();
		$this->multilingual->init();
		$this->themes->init();
		$this->plugins->init();
		$this->bulk_integrations->init();
		$this->database->register_tables();
		$this->index->init();
		$this->index_pusher->init();
		$this->request->init();
		$this->blocks->init();
		$this->widgets->init();
		$this->fibofilters_shortcode->init();
		$this->fibofilters_applied_filters_shortcode->init();
		$this->fibofilters_show_more_products_btn_shortcode->init();
		$this->fibofilters_show_previous_products_btn_shortcode->init();
		$this->fibofilters_infinite_scroll_trigger_shortcode->init();
		$this->fibofilters_ordering_shortcode->init();
		$this->fibofilters_pagination_shortcode->init();

		if ( is_admin() ) {
			$this->troubleshooting->init();
			$this->container->dich()->add_action( // @phpstan-ignore-line
				'plugins_loaded',
				[ 'config.menu', 'init' ],
				20
			);
			$this->container->dich()->add_action( // @phpstan-ignore-line
				'admin_enqueue_scripts',
				[ 'config.admin_assets_loader', 'enqueue_admin_assets' ]
			);
			$this->container->dich()->add_action( // @phpstan-ignore-line
				'admin_init',
				[ 'config.install', 'maybe_install' ],
				5
			);
		}

		$this->container->dich()->add_action( // @phpstan-ignore-line
			IndexPusher::HOOK,
			[ 'config.install', 'maybe_install' ],
			5
		);

		$this->container->dich()->add_action( // @phpstan-ignore-line
			'fibofilters/install/install_without_reindexing',
			[ 'config.install', 'install_without_reindexing' ],
			5
		);

		$this->container->dich()->add_action( // @phpstan-ignore-line
			'cli_init',
			[ 'config.wpcli', 'init' ]
		);

		// Disabling REST API functionality when updating a plugin due to compatibility issues.
		if ( ! defined( 'IFRAME_REQUEST' ) || ! IFRAME_REQUEST ) {
			$this->container->dich()->add_action( // @phpstan-ignore-line
				'rest_api_init',
				[ 'api.api', 'init' ]
			);
		}

		$this->container->dich()->add_action( // @phpstan-ignore-line
			'admin_bar_menu',
			[ 'config.admin_bar', 'init' ],
			150
		);

		$this->filters_debugger->init();

		do_action( 'fibofilters/initialized', Env::$version );
	}

	public function late_initialize() {
		if ( ! $this->requirements->check_all_requirements() ) {
			return;
		}

		$this->plugins->late_init();
	}

	public function load_translations(): void {
		load_plugin_textdomain( Env::$plugin_slug, false, Env::$languages_path_rel );
	}

	/**
	 * Add action from plugin
	 *
	 * @param string $hook_name Hook name.
	 * @param string $alias Class aliast (or full name).
	 * @param string $method Method inside class.
	 * @param int    $priority Priority.
	 */
	public function add_action( string $hook_name, string $alias, string $method, int $priority = 10 ): void {
		if ( $this->container->has( $alias ) ) {
			try {
				$object = $this->container->get( $alias );
				add_action( $hook_name, [ $object, $method ], $priority );
			} catch ( \Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
				// There is no need to do anything.
			}
		}
	}

	/**
	 * Remove action from plugin
	 *
	 * @param string $hook_name Hook name.
	 * @param string $alias Class aliast (or full name).
	 * @param string $method Method inside class.
	 * @param int    $priority Priority.
	 */
	public function remove_action( string $hook_name, string $alias, string $method, int $priority = 10 ): void {
		if ( $this->container->has( $alias ) ) {
			try {
				$object = $this->container->get( $alias );
				remove_action( $hook_name, [ $object, $method ], $priority );
			} catch ( \Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
				// There is no need to do anything.
			}
		}
	}
}
