<?php
/**
 * Main controller for bootstrapping the plugin.
 *
 * @package Awesomemotive\Rewardswp\Controllers
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Controllers;

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

use Awesomemotive\Rewardswp\Database\UpgradeManager;
use Awesomemotive\Rewardswp\Interfaces\ControllerInterface;
use Awesomemotive\Rewardswp\Services\AssetsService;
use Awesomemotive\Rewardswp\Services\PanelService;
use Awesomemotive\Rewardswp\Settings\Options\RewardsWidget\BrandForegroundColorOption;
use DI\Container;
use DI\DependencyException;
use DI\NotFoundException;
use Exception;

use function Awesomemotive\Rewardswp\Helpers\frontend_ajax_url;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;

class MainController implements ControllerInterface {
	/**
	 * DI container instance.
	 *
	 * @since 1.0.0
	 *
	 * @var Container
	 */
	private Container $container;

	/**
	 * Assets service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var AssetsService
	 */
	private AssetsService $assets_service;

	/**
	 * Panel service instance.
	 *
	 * @since 1.1.0
	 *
	 * @var PanelService
	 */
	private PanelService $panel_service;

	/**
	 * List of global controller classes to be executed.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private array $global_controllers;

	/**
	 * List of controller classes to be executed.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private array $controllers;

	/**
	 * Upgrade manager instance.
	 *
	 * @since 1.0.1
	 *
	 * @var UpgradeManager
	 */
	private UpgradeManager $upgrade_manager;

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param Container      $container
	 * @param AssetsService  $assets_service
	 * @param UpgradeManager $upgrade_manager
	 * @param PanelService   $panel_service
	 * @throws DependencyException
	 *
	 * @throws NotFoundException|DependencyException If fails to get resource from container.
	 */
	public function __construct(
		Container $container,
		AssetsService $assets_service,
		UpgradeManager $upgrade_manager,
		PanelService $panel_service
	) {
		$this->container          = $container;
		$this->assets_service     = $assets_service;
		$this->upgrade_manager    = $upgrade_manager;
		$this->panel_service      = $panel_service;
		$this->global_controllers = $container->get( 'global_controllers_classes' );
		$this->controllers        = $container->get( 'main_controllers_classes' );
	}

	/**
	 * Load controllers.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 * @throws DependencyException
	 * @throws Exception
	 */
	public function init() {
		// Database upgrades must run prior to anything else.
		$this->upgrade_manager->run_upgrades();

		// Load global controllers.
		foreach ( $this->global_controllers as $controller_class ) {
			$this->container->get( $controller_class )->init();
		}

		if ( ! $this->panel_service->should_display_panel() ) {
			return; // Bail if it is not fully configured and active.
		}

		// Delay asset hooks until template_redirect when WC/EDD functions are available.
		add_action( 'template_redirect', [ $this, 'setup_asset_hooks' ] );

		// Load controllers.
		foreach ( $this->controllers as $controller_class ) {
			$this->container->get( $controller_class )->init();
		}
	}

	/**
	 * Setup asset hooks after checking visibility filter.
	 *
	 * This method runs on template_redirect to ensure WooCommerce and EDD
	 * conditional functions are available for checking page context.
	 *
	 * @since 1.1.0
	 *
	 * @return void
	 */
	public function setup_asset_hooks(): void {
		/**
		 * Allow plugins to control asset loading.
		 *
		 * @since 1.1.0
		 *
		 * @param bool $should_load Whether assets should be loaded.
		 */
		$should_load_assets = apply_filters( 'rewardswp_should_load_main_assets', true );

		if ( ! $should_load_assets ) {
			return; // Don't load assets at all.
		}

		// Assets will load, now check if widget should render.
		add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
		add_action( 'wp_enqueue_scripts', [ $this, 'action_print_custom_css_variables' ], 20 );

		/**
		 * Allow plugins to control widget visibility.
		 *
		 * @since 1.1.0
		 *
		 * @param bool $is_visible Whether the widget should be visible or not.
		 */
		$is_visible = apply_filters( 'rewardswp_is_rewards_widget_visible', true );

		if ( ! $is_visible ) {
			return; // Assets loaded, but widget won't render.
		}

		// Widget will render (AdvocateController handles this).
	}



	/**
	 * Register global CSS and JS.
	 *
	 * Just register, enqueue must be done when necessary.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function enqueue_scripts(): void {
		$data = wp_json_encode(
			[
				'ajaxUrl'          => frontend_ajax_url(),
				'mainCssUrl'       => $this->assets_service->get_file_url( $this->assets_service->get_main_css_filename() ),
				'brandForegroundColor' => get_option_value( BrandForegroundColorOption::class ),
			]
		);

		// The main script is registered at this point, so it is safe to add inline data here.
		wp_add_inline_script(
			$this->assets_service::MAIN_SCRIPT_HANDLE,
			"const rewardswpMainVars=$data",
			'before'
		);

		$this->assets_service->enqueue_script( $this->assets_service::MAIN_SCRIPT_HANDLE );
	}

	/**
	 * Print custom CSS variables.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function action_print_custom_css_variables(): void {
		$this->assets_service->print_brand_css_variables();
	}
}
