<?php
/**
 * Service container wrapper for dependency injection.
 *
 * @package Firevert\Core
 */

declare ( strict_types=1 );

namespace Ilabs\Firevert;

use Exception;
use Ilabs\Firevert\Core\Api\Controller\ProductCategoriesController;
use Ilabs\Firevert\Core\Api\Controller\ProductsController;
use Ilabs\Firevert\Core\Api\Validator\RequestValidator;
use Ilabs\Firevert\Core\Repository\Cache\CacheRepository;
use Ilabs\Firevert\Core\Hooks\HooksLoader;
use Ilabs\Firevert\Core\ModuleManager;
use Ilabs\Firevert\Core\ServiceContainer;
use Ilabs\Firevert\Core\Settings\Form\SettingsFormHandler;
use Ilabs\Firevert\Core\Settings\Form\SettingsStorageService;
use Ilabs\Firevert\Core\Settings\Registrar\CoreSettingsRegistrar;
use Ilabs\Firevert\Core\Settings\Registry\SettingsRegistry;
use Ilabs\Firevert\Core\Settings\Registrar\SettingsApiRegistrar;
use Ilabs\Firevert\Core\Settings\UI\SettingsPageRenderer;
use Ilabs\Firevert\Core\Form\Sanitization\MetaFieldSanitizer;
use Isolated\Firevert\Ilabs\Ilabs_Plugin\Abstract_Ilabs_Plugin;
use Isolated\Firevert\Ilabs\Ilabs_Plugin\Woocommerce_Logger;

/**
 * Main Firevert plugin class.
 */
class Firevert extends Abstract_Ilabs_Plugin {

	public const SHORT_SLUG = 'Firevert';

	/**
	 * DI container instance.
	 *
	 * @var ServiceContainer
	 */
	private ServiceContainer $container;

	/**
	 * Constructor.
	 *
	 * @param ServiceContainer $container Service container.
	 *
	 * @since 1.0.0
	 */
	public function __construct( ServiceContainer $container ) {
		$this->container = $container;
	}

	/**
	 * Method executed before init.
	 *
	 * @return void
	 * @throws Exception When initialization fails.
	 *
	 * @since 1.0.0
	 */
	protected function before_init(): void {
		do_action( 'firevert_before_init_ready', $this->container );
	}

	/**
	 * Hooked into plugins_loaded.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	protected function plugins_loaded_hooks(): void {
		// TODO: Implement plugins_loaded_hooks() method.
	}

	/**
	 * Checks if logger is enabled.
	 *
	 * @return bool
	 *
	 * @since 1.0.0
	 */
	protected function is_logger_enabled(): bool {
		return \get_option( 'logger_enabled' );
	}

	/**
	 * Returns the DI container.
	 *
	 * @return ServiceContainer
	 *
	 * @since 1.0.0
	 */
	public function get_container(): ServiceContainer {
		return $this->container;
	}

	/**
	 * Enqueue frontend scripts.
	 *
	 * @return void
	 * @throws Exception When enqueueing fails.
	 *
	 * @since 1.0.0
	 */
	public function enqueue_frontend_scripts(): void {
	}

	/**
	 * Enqueue dashboard scripts.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	public function enqueue_dashboard_scripts(): void {
	}

	/**
	 * Init plugin logic.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	public function init(): void {
		$this->register_settings_services();
		$this->register_api_services();
		$this->register_endpoints();
		$this->register_modules();

		do_action( 'firevert_init_ready', $this->container );
	}

	/**
	 * Creates a new instance of the WooCommerce logger.
	 *
	 * @param string $log_id Identifier used to prefix the logger entries.
	 *
	 * @return Woocommerce_Logger
	 *
	 * @since 1.0.0
	 */
	public function create_logger( string $log_id ): Woocommerce_Logger {
		return new Woocommerce_Logger( $log_id );
	}

	/**
	 * Returns WooCommerce logger instance.
	 *
	 * @param string|null $log_id Optional log ID.
	 *
	 * @return Woocommerce_Logger
	 * @throws Exception If logger configuration is invalid.
	 *
	 * @since 1.0.0
	 */
	public function get_woocommerce_logger( ?string $log_id = null ): Woocommerce_Logger {
		$log_id = $log_id
			? $this->prefix_by_short_slug( $log_id )
			: $this->get_from_config( 'slug' );

		$logger = $this->create_logger( $log_id );

		if ( ! $this->is_logger_enabled() ) {
			$logger->set_null_logger( true );
		}

		return $logger;
	}

	/**
	 * Prefixes a string with SHORT_SLUG.
	 *
	 * @param string $txt String to prefix.
	 *
	 * @return string
	 *
	 * @since 1.0.0
	 */
	public function prefix_by_short_slug( string $txt ): string {
		return self::SHORT_SLUG . '_' . $txt;
	}

	/**
	 * Registers all settings-related services in the container.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	private function register_settings_services(): void {
		$registry  = new SettingsRegistry();
		$storage   = new SettingsStorageService();
		$form      = new SettingsFormHandler( $registry, $storage );
		$api       = new SettingsApiRegistrar( $registry );
		$view      = new SettingsPageRenderer( $registry );
		$sanitizer = new MetaFieldSanitizer();
		$cache     = new CacheRepository();

		$this->container->set( 'settings_registry', $registry );
		$this->container->set( 'settings_storage', $storage );
		$this->container->set( 'settings_form_handler', $form );
		$this->container->set( 'settings_api_registrar', $api );
		$this->container->set( 'settings_page_renderer', $view );
		$this->container->set( 'meta_field_sanitizer', $sanitizer );
		$this->container->set( 'cache_repository', $cache );

		( new CoreSettingsRegistrar( $registry ) )->register();
		( new HooksLoader( $this->container ) )->register();
	}

	/**
	 * Registers API-related services in the container.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	private function register_api_services(): void {
		$request_validator = new RequestValidator();
		$this->container->set( 'request_validator', $request_validator );
	}

	/**
	 * Registers API endpoints for the application.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	private function register_endpoints(): void {
		( new ProductsController() )->register_routes();
		( new ProductCategoriesController() )->register_routes();
	}

	/**
	 * Registers and initializes all modules.
	 *
	 * @return void
	 *
	 * @since 1.0.0
	 */
	private function register_modules(): void {
		/**
		 * Get from DI container.
		 *
		 * @var ModuleManager $module_manager
		 */
		$module_manager = $this->container->get( 'module_manager' );
		$storage        = $this->container->get( 'settings_storage' );
		$module_manager->register_modules( $this->container, $storage );
	}
}
