<?php
/**
 * Admin Color Customizer module.
 *
 * @package WP_PowerSuite\AdminColorCustomizer
 */

namespace WP_PowerSuite\AdminColorCustomizer;

use WP_PowerSuite\Core\AbstractModule;
use WP_PowerSuite\Core\Contracts\DataLocationsInterface;
use WP_PowerSuite\Core\NetworkScope;

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

require_once __DIR__ . '/includes/class-feature-gate.php';
require_once __DIR__ . '/includes/class-settings.php';
require_once __DIR__ . '/includes/class-scheme-registry.php';
require_once __DIR__ . '/includes/class-css-generator.php';
require_once __DIR__ . '/includes/class-user-scheme-resolver.php';
require_once __DIR__ . '/includes/class-environment-badge.php';
require_once __DIR__ . '/includes/class-accessibility.php';
require_once __DIR__ . '/includes/class-admin-helpers.php';
wp_powersuite_require_freemium_file( 'admin-color-customizer', 'includes/class-role-resolver.php' );
wp_powersuite_require_freemium_file( 'admin-color-customizer', 'includes/premium.php' );

class Module extends AbstractModule implements DataLocationsInterface {

	public const MODULE_ID = 'admin-color-customizer';

	public const VERSION = '1.0.14';

	public const PAGE_SLUG = 'powersuite-admin-color-customizer';

	private ?User_Scheme_Resolver $resolver = null;

	private ?CSS_Generator $css_generator = null;

	/** @var array<string, mixed>|null */
	private ?array $settings_cache = null;

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Admin Color Customizer', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::VERSION;
	}

	public function getDescription(): string {
		return __( 'Customize WordPress admin dashboard colors with presets, role mapping, live preview, and safe CSS generation.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return [ 'admin', 'ajax', 'login', 'frontend' ];
	}

	public function getDataLocations(): array {
		return [
			'option_store_keys' => [ self::MODULE_ID ],
		];
	}

	/**
	 * @return array<string, mixed>
	 */
	public static function getDefaultSettings(): array {
		return Settings::get_default_settings();
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>
	 */
	public static function sanitizeSettings( array $settings ): array {
		return Settings::sanitize( $settings );
	}

	/**
	 * @return array<string, mixed>
	 */
	public function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}

		$this->settings_cache = Settings::get_effective_settings();

		return $this->settings_cache;
	}

	protected function registerHooks(): void {
		add_action( 'wp_ajax_wpps_acc_save_settings', [ $this, 'ajaxSaveSettings' ] );
		add_action( 'wp_ajax_wpps_acc_preview_css', [ $this, 'ajaxPreviewCss' ] );
		add_action( 'wp_ajax_wpps_acc_reset_scheme', [ $this, 'ajaxResetScheme' ] );
		add_action( 'wp_ajax_wpps_acc_check_contrast', [ $this, 'ajaxCheckContrast' ] );
		add_action( 'wp_ajax_wpps_acc_scheme_css', [ $this, 'ajaxSchemeCss' ] );

		add_action(
			'wp_powersuite_module_settings_saved',
			function ( string $module_id, array $settings ): void {
				if ( $module_id !== self::MODULE_ID ) {
					return;
				}
				$this->settings_cache = Settings::sanitize( $settings );
			},
			10,
			2
		);

		if ( ! Settings::is_emergency_disabled() ) {
			$settings = $this->getSettings();

			add_filter( 'get_user_option_admin_color', [ $this, 'filterAdminColor' ], 10, 3 );
			add_filter( 'admin_body_class', [ $this, 'filterAdminBodyClass' ] );
			add_action( 'admin_init', [ $this, 'registerAdminColorSchemes' ], 20 );

			if ( ( $settings['mode'] ?? '' ) === 'per_user_selectable' || ( $settings['mode'] ?? '' ) === 'global_default' ) {
				add_action( 'admin_color_scheme_picker', [ $this, 'renderColorSchemePickerNote' ] );
			}

			add_action( 'admin_enqueue_scripts', [ $this, 'enqueueAdminSchemeCss' ], 999 );
			add_action( 'wp_enqueue_scripts', [ $this, 'enqueueFrontendAdminBarCss' ], 20 );

			( new Environment_Badge() )->register_hooks( $settings );
		}

		if ( is_admin() ) {
			add_action( $this->adminMenuHook(), [ $this, 'registerMenu' ], 25 );
			add_action( 'admin_enqueue_scripts', [ $this, 'enqueueModuleAdminAssets' ] );
		}
	}

	public function registerMenu(): void {
		if ( ! $this->canManagePlugin() ) {
			return;
		}

		$this->registerPowerSuiteSubmenu(
			__( 'Admin Color Customizer', 'wp-powersuite' ),
			__( 'Admin Colors', 'wp-powersuite' ),
			self::PAGE_SLUG,
			[ $this, 'renderPage' ]
		);
	}

	public function renderPage(): void {
		if ( ! $this->canManagePlugin() ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-powersuite' ) );
		}

		$view = self::resolveView(
			isset( $_GET['view'] ) ? (string) wp_unslash( $_GET['view'] ) : 'setup'
		);

		$settings       = $this->getSettings();
		$site_settings  = Settings::get_site_settings();
		$network_settings = Settings::get_network_settings();
		$registry       = Scheme_Registry::instance();
		$schemes        = $registry->get_all_schemes( $settings );
		$built_in       = $registry->get_built_in_schemes();
		$active_scheme  = $registry->get_scheme( (string) ( $settings['active_scheme'] ?? 'powersuite_blue' ), $settings );
		$accessibility  = $active_scheme ? ( new Accessibility() )->check_scheme( $active_scheme ) : [];
		$screen_url     = NetworkScope::adminUrl( 'admin.php', [ 'page' => self::PAGE_SLUG ] );
		$settings_source = Settings::get_settings_source_label();
		$editable_roles = get_editable_roles();
		$premium_unlocked = FeatureGate::isPremiumLicensed();

		$ui = defined( 'WP_POWERSUITE_SRC_DIR' )
			? WP_POWERSUITE_SRC_DIR . 'Admin' . DIRECTORY_SEPARATOR . 'ModuleSettingsUi.php'
			: '';
		if ( $ui !== '' && is_readable( $ui ) ) {
			require_once $ui;
		}

		include __DIR__ . '/admin/page-admin-color-customizer.php';
	}

	private static function resolveView( string $view ): string {
		$view = sanitize_key( $view );

		$allowed = [
			'setup',
			'colors',
			'advanced',
			// Legacy slugs redirect in resolveView.
			'overview',
			'presets',
			'builder',
			'roles',
			'environment',
			'settings',
		];

		return in_array( $view, $allowed, true ) ? self::normalizeView( $view ) : 'setup';
	}

	private static function normalizeView( string $view ): string {
		return match ( $view ) {
			'overview', 'presets', 'settings' => 'setup',
			'builder' => 'colors',
			'roles', 'environment' => 'advanced',
			default => $view,
		};
	}

	public function registerAdminColorSchemes(): void {
		if ( Settings::is_emergency_disabled() ) {
			return;
		}

		$settings = $this->getSettings();
		$mode = (string) ( $settings['mode'] ?? 'disabled' );

		if ( $mode === 'disabled' ) {
			return;
		}

		if ( ! in_array( $mode, [ 'global_default', 'per_user_selectable' ], true ) ) {
			return;
		}

		Scheme_Registry::instance()->register_wp_admin_schemes( $settings );
	}

	/**
	 * Append scoped body classes for the active admin color scheme.
	 */
	public function filterAdminBodyClass( string $classes ): string {
		if ( Settings::is_emergency_disabled() || $this->isModuleAdminScreen( $this->currentAdminHook() ) ) {
			return $classes;
		}

		$settings = $this->getSettings();
		if ( ! $this->getResolver()->should_output_admin_css( $settings ) ) {
			return $classes;
		}

		$scheme = $this->getResolver()->resolve_scheme( $settings );
		if ( $scheme === null ) {
			return $classes;
		}

		$scheme_id = sanitize_html_class( (string) ( $scheme['id'] ?? 'powersuite_blue' ) );
		if ( $scheme_id === '' ) {
			return $classes;
		}

		return trim( $classes . ' wpps-acc-enabled wpps-acc-scheme-' . $scheme_id );
	}

	public function ajaxSchemeCss(): void {
		if ( ! is_user_logged_in() ) {
			status_header( 403 );
			exit;
		}

		$scheme_id = isset( $_GET['scheme'] ) ? sanitize_key( (string) wp_unslash( $_GET['scheme'] ) ) : '';
		$nonce     = isset( $_GET['_wpnonce'] ) ? (string) wp_unslash( $_GET['_wpnonce'] ) : '';

		if ( $scheme_id === '' || ! wp_verify_nonce( $nonce, 'wpps_acc_scheme_css_' . $scheme_id ) ) {
			status_header( 403 );
			exit;
		}

		$settings = $this->getSettings();
		$scheme   = Scheme_Registry::instance()->get_scheme( $scheme_id, $settings );

		if ( $scheme === null ) {
			status_header( 404 );
			exit;
		}

		nocache_headers();
		header( 'Content-Type: text/css; charset=UTF-8' );
		header( 'X-Robots-Tag: noindex' );

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- text/css body; generator emits sanitized stylesheet rules.
		echo wp_strip_all_tags( $this->getCssGenerator()->generate( $scheme, $settings, 'admin', false ) );
		exit;
	}

	public function renderColorSchemePickerNote( $user ): void {
		echo '<p class="description">' . esc_html__( 'Custom PowerSuite color schemes appear alongside WordPress core schemes.', 'wp-powersuite' ) . '</p>';
	}

	/**
	 * @param mixed         $value  Current admin color scheme slug.
	 * @param string        $option Option name (admin_color).
	 * @param \WP_User|mixed $user  User whose option is being retrieved.
	 */
	public function filterAdminColor( $value, string $option, $user ) {
		unset( $option );

		$user_id = $user instanceof \WP_User ? (int) $user->ID : (int) $user;
		if ( $user_id <= 0 ) {
			return $value;
		}

		return $this->getResolver()->filter_admin_color_option( $value, 'admin_color', $user_id );
	}

	public function enqueueAdminSchemeCss( string $hook ): void {
		if ( Settings::is_emergency_disabled() ) {
			return;
		}

		$settings = $this->getSettings();
		if ( ! $this->getResolver()->should_output_admin_css( $settings ) ) {
			return;
		}

		// On the module's own page, colour only the admin chrome (menu, bar,
		// links, theme variables) for the ACTIVE scheme being customised — so
		// the user immediately sees what they're editing — while leaving the
		// settings controls (buttons, inputs, tables) native for predictable
		// editing.
		if ( $this->isModuleAdminScreen( $hook ) ) {
			$active_id = sanitize_key( (string) ( $settings['active_scheme'] ?? 'powersuite_blue' ) );
			$scheme    = Scheme_Registry::instance()->get_scheme( $active_id, $settings );
			if ( $scheme === null ) {
				return;
			}

			$this->registerOutputStylesheet( 'wpps-acc-admin-scheme', [ 'colors' ] );
			wp_add_inline_style( 'wpps-acc-admin-scheme', $this->getCssGenerator()->generate_admin_chrome( $scheme ) );

			return;
		}

		$scheme = $this->getResolver()->resolve_scheme( $settings );
		if ( $scheme === null ) {
			return;
		}

		$css = $this->getCssGenerator()->generate( $scheme, $settings, 'admin' );

		// Never remove the core `colors` stylesheet: admin-header.php enqueues
		// ONLY `colors`, and the entire admin CSS tree (wp-admin -> common,
		// forms, admin-menu, dashboard, buttons, ...) is loaded as its
		// dependency chain. Dequeuing/deregistering it would leave the whole
		// admin unstyled. Instead, we depend on `colors` so the full core tree
		// loads first and our scheme colors are layered on top.
		$this->registerOutputStylesheet( 'wpps-acc-admin-scheme', [ 'colors' ] );
		wp_add_inline_style( 'wpps-acc-admin-scheme', $css );
	}

	public function enqueueFrontendAdminBarCss(): void {
		if ( Settings::is_emergency_disabled() ) {
			return;
		}

		$settings = $this->getSettings();
		if ( ! $this->getResolver()->should_output_frontend_admin_bar_css( $settings ) ) {
			return;
		}

		$scheme = $this->getResolver()->resolve_scheme( $settings );
		if ( $scheme === null ) {
			return;
		}

		wp_enqueue_style( 'admin-bar' );
		$this->registerOutputStylesheet( 'wpps-acc-admin-bar-scheme', [ 'admin-bar' ] );
		wp_add_inline_style( 'wpps-acc-admin-bar-scheme', $this->getCssGenerator()->generate( $scheme, $settings, 'admin_bar' ) );
	}

	public function enqueueLoginCss(): void {
		if ( Settings::is_emergency_disabled() ) {
			return;
		}

		$settings = $this->getSettings();
		if ( ! $this->getResolver()->should_output_login_css( $settings ) ) {
			return;
		}

		$scheme = $this->getResolver()->resolve_scheme( $settings );
		if ( $scheme === null ) {
			return;
		}

		wp_enqueue_style( 'login' );
		$this->registerOutputStylesheet( 'wpps-acc-login-scheme', [ 'login' ] );
		wp_add_inline_style( 'wpps-acc-login-scheme', $this->getCssGenerator()->generate( $scheme, $settings, 'login' ) );
	}

	/**
	 * @param list<string> $deps Handles this override must load after.
	 */
	private function registerOutputStylesheet( string $handle, array $deps = [] ): void {
		$base = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';

		wp_register_style(
			$handle,
			$base . 'modules/admin-color-customizer/assets/css/admin-color-customizer-output.css',
			$deps,
			self::VERSION
		);
		wp_enqueue_style( $handle );
	}

	public function enqueueModuleAdminAssets( string $hook ): void {
		if ( ! $this->isModuleAdminScreen( $hook ) ) {
			return;
		}

		$base = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';

		$this->enqueueColorPanelAssets();
		$this->enqueueCustomCssEditorAssets();

		wp_enqueue_style(
			'wpps-admin-color-customizer',
			$base . 'modules/admin-color-customizer/assets/css/admin-color-customizer.css',
			[ 'wp-powersuite-admin', 'wp-powersuite-color-panel' ],
			self::VERSION
		);

		wp_enqueue_script(
			'wpps-admin-color-customizer',
			$base . 'modules/admin-color-customizer/assets/js/admin-color-customizer.js',
			[ 'wp-powersuite-color-panel', 'code-editor' ],
			self::VERSION,
			true
		);

		$settings = $this->getSettings();
		$registry = Scheme_Registry::instance();

		wp_localize_script(
			'wpps-admin-color-customizer',
			'wppsAdminColorCustomizer',
			[
				'ajaxUrl'         => admin_url( 'admin-ajax.php' ),
				'nonce'           => wp_create_nonce( 'wpps_acc_admin' ),
				'currentView'     => self::resolveView(
					isset( $_GET['view'] ) ? (string) wp_unslash( $_GET['view'] ) : 'setup'
				),
				'settings'        => $settings,
				'schemes'         => $registry->get_all_schemes( $settings ),
				'builtInSchemes'  => array_keys( $registry->get_built_in_schemes() ),
				'accessibleDefaults' => Settings::get_accessible_defaults(),
				'settingsSource'  => Settings::get_settings_source_label(),
				'isMultisite'     => is_multisite(),
				'canManageNetwork'=> Settings::can_manage_network_settings(),
				'premiumUnlocked' => FeatureGate::isPremiumLicensed(),
				'licenseUrl'      => FeatureGate::upsellUrl(),
				'strings'         => [
					'saved'              => __( 'Settings saved.', 'wp-powersuite' ),
					'saving'             => __( 'Saving…', 'wp-powersuite' ),
					'errorGeneric'       => __( 'Something went wrong. Please try again.', 'wp-powersuite' ),
					'contrastWarning'    => __( 'Contrast warning', 'wp-powersuite' ),
					'contrastPass'       => __( 'Contrast OK', 'wp-powersuite' ),
					'confirmResetAll'    => __( 'Reset all module settings to defaults?', 'wp-powersuite' ),
					'confirmResetScheme' => __( 'Reset the current scheme to built-in defaults?', 'wp-powersuite' ),
					'resetAccessibleApplied' => __( 'Accessible defaults applied to the preview. Click Save settings to persist.', 'wp-powersuite' ),
					'customCssWarning'   => __( 'Custom CSS can affect admin security and layout. Enable only if you trust the source.', 'wp-powersuite' ),
				],
			]
		);
	}

	public function ajaxSaveSettings(): void {
		$this->assertAjaxRequest();

		$raw = $this->decodePostedJson( 'settings' );
		if ( $raw === null ) {
			wp_send_json_error( [ 'message' => __( 'Invalid settings payload.', 'wp-powersuite' ) ] );
		}

		$scope = isset( $_POST['save_scope'] ) ? sanitize_key( (string) wp_unslash( $_POST['save_scope'] ) ) : 'site';

		$existing = $scope === 'network' && Settings::can_manage_network_settings()
			? Settings::get_network_settings()
			: Settings::get_stored_settings();
		$raw = FeatureGate::preservePremiumSettingsOnSave( $raw, $existing );

		if ( $scope === 'network' && Settings::can_manage_network_settings() ) {
			$sanitized = Settings::sanitize( $raw, 'network' );
			Settings::save_network_settings( $sanitized );
		} else {
			$sanitized = Settings::sanitize( $raw, 'site' );
			Settings::save_site_settings( $sanitized );
		}

		$this->settings_cache = Settings::get_effective_settings();

		$active = Scheme_Registry::instance()->get_scheme( (string) ( $sanitized['active_scheme'] ?? '' ), $sanitized );
		$warnings = $active ? ( new Accessibility() )->check_scheme( $active ) : [];

		wp_send_json_success(
			[
				'settings'     => $this->settings_cache,
				'accessibility'=> $warnings,
			]
		);
	}

	public function ajaxPreviewCss(): void {
		$this->assertAjaxRequest();

		$scheme_raw = $this->decodePostedJson( 'scheme' );
		if ( $scheme_raw === null ) {
			wp_send_json_error( [ 'message' => __( 'Invalid scheme payload.', 'wp-powersuite' ) ] );
		}

		$scheme = $this->resolvePostedSchemeForPreview( $scheme_raw );
		if ( $scheme === null ) {
			wp_send_json_error( [ 'message' => __( 'Invalid color values.', 'wp-powersuite' ) ] );
		}

		$settings = $this->getSettings();
		$css      = $this->getCssGenerator()->generate( $scheme, $settings, 'admin' );
		$warnings = ( new Accessibility() )->check_scheme( $scheme );

		wp_send_json_success(
			[
				'css'          => $css,
				'accessibility'=> $warnings,
			]
		);
	}

	public function ajaxResetScheme(): void {
		$this->assertAjaxRequest();

		$reset_type = isset( $_POST['reset_type'] ) ? sanitize_key( (string) wp_unslash( $_POST['reset_type'] ) ) : 'scheme';
		$settings   = Settings::get_site_settings();

		if ( $reset_type === 'all' ) {
			$settings = Settings::get_default_settings();
			Settings::save_site_settings( $settings );
			$this->settings_cache = Settings::get_effective_settings();
			wp_send_json_success( [ 'settings' => $this->settings_cache ] );
		}

		$scheme_id = isset( $_POST['scheme_id'] ) ? sanitize_key( (string) wp_unslash( $_POST['scheme_id'] ) ) : (string) ( $settings['active_scheme'] ?? '' );
		$built_in  = Scheme_Registry::instance()->get_built_in_schemes();

		if ( $scheme_id !== '' && isset( $built_in[ $scheme_id ] ) ) {
			wp_send_json_success(
				[
					'scheme' => $built_in[ $scheme_id ],
				]
			);
		}

		if ( FeatureGate::isPremiumLicensed() && isset( $settings['custom_schemes'][ $scheme_id ] ) ) {
			unset( $settings['custom_schemes'][ $scheme_id ] );
			Settings::save_site_settings( $settings );
		}

		$defaults = Settings::get_accessible_defaults();
		wp_send_json_success(
			[
				'scheme' => array_merge(
					[
						'id'       => $scheme_id !== '' ? $scheme_id : 'custom_scheme',
						'name'     => __( 'Custom Scheme', 'wp-powersuite' ),
						'built_in' => false,
					],
					$defaults,
					[ 'custom_css' => '' ]
				),
			]
		);
	}

	public function ajaxCheckContrast(): void {
		$this->assertAjaxRequest();

		$scheme_raw = $this->decodePostedJson( 'scheme' );
		if ( $scheme_raw === null ) {
			wp_send_json_error( [ 'message' => __( 'Invalid scheme payload.', 'wp-powersuite' ) ] );
		}

		$scheme = $this->resolvePostedSchemeForPreview( $scheme_raw );
		if ( $scheme === null ) {
			wp_send_json_error( [ 'message' => __( 'Invalid color values.', 'wp-powersuite' ) ] );
		}

		wp_send_json_success(
			[
				'warnings' => ( new Accessibility() )->check_scheme( $scheme ),
			]
		);
	}

	/**
	 * @param array<string, mixed> $scheme_raw
	 * @return array<string, mixed>|null
	 */
	private function resolvePostedSchemeForPreview( array $scheme_raw ): ?array {
		$registry = Scheme_Registry::instance();

		if ( FeatureGate::isPremiumLicensed() && class_exists( Premium::class, false ) ) {
			$scheme = Premium::sanitize_scheme( $scheme_raw, 'save' );
			if ( $scheme !== null ) {
				return $scheme;
			}

			$existing = $registry->get_scheme( (string) ( $scheme_raw['id'] ?? '' ), $this->getSettings() );
			if ( $existing !== null ) {
				return Premium::apply_color_overrides( $existing, $scheme_raw );
			}

			return null;
		}

		$id       = sanitize_key( (string) ( $scheme_raw['id'] ?? '' ) );
		$existing = $registry->get_scheme( $id, $this->getSettings() );
		if ( $existing !== null && ! empty( $existing['built_in'] ) ) {
			return $existing;
		}

		return null;
	}

	private function assertAjaxRequest(): void {
		if ( ! check_ajax_referer( 'wpps_acc_admin', 'nonce', false ) ) {
			wp_send_json_error(
				[ 'message' => __( 'Security check failed. Refresh the page and try again.', 'wp-powersuite' ) ],
				403
			);
		}

		if ( ! NetworkScope::canManagePlugin() ) {
			wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'wp-powersuite' ) ], 403 );
		}
	}

	/**
	 * @return array<string, mixed>|null
	 */
	private function decodePostedJson( string $key ): ?array {
		if ( ! isset( $_POST[ $key ] ) ) {
			return null;
		}

		$raw = wp_unslash( $_POST[ $key ] );
		if ( is_array( $raw ) ) {
			return $raw;
		}

		if ( ! is_string( $raw ) || $raw === '' ) {
			return null;
		}

		$decoded = json_decode( $raw, true );

		return is_array( $decoded ) ? $decoded : null;
	}

	private function isModuleAdminScreen( string $hook ): bool {
		$hooks = [
			'wp-powersuite_page_' . self::PAGE_SLUG,
			'powersuite_page_' . self::PAGE_SLUG,
		];

		$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( (string) $_GET['page'] ) ) : '';

		return in_array( $hook, $hooks, true ) || $page === self::PAGE_SLUG;
	}

	private function currentAdminHook(): string {
		global $hook_suffix;

		return is_string( $hook_suffix ) ? $hook_suffix : '';
	}

	private function enqueueColorPanelAssets(): void {
		$base    = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';
		$version = defined( 'WP_POWERSUITE_VERSION' ) ? WP_POWERSUITE_VERSION : self::VERSION;

		if ( $base === '' ) {
			return;
		}

		if ( ! wp_style_is( 'wp-powersuite-color-panel', 'registered' ) ) {
			wp_register_style(
				'wp-powersuite-color-panel',
				$base . 'assets/admin/color-panel.css',
				[ 'wp-powersuite-admin' ],
				$version
			);
		}
		wp_enqueue_style( 'wp-powersuite-color-panel' );

		if ( ! wp_script_is( 'wp-powersuite-color-panel', 'registered' ) ) {
			wp_register_script(
				'wp-powersuite-color-panel',
				$base . 'assets/admin/color-panel.js',
				[ 'jquery' ],
				$version,
				true
			);
		}
		wp_enqueue_script( 'wp-powersuite-color-panel' );
	}

	private function enqueueCustomCssEditorAssets(): void {
		wp_enqueue_code_editor( [ 'type' => 'text/css' ] );

		$plugin_dir = defined( 'WP_POWERSUITE_PLUGIN_DIR' ) ? WP_POWERSUITE_PLUGIN_DIR : '';
		$plugin_url = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';
		if ( $plugin_dir === '' || $plugin_url === '' ) {
			return;
		}

		$rel  = 'modules/code-snippet/assets/cs-admin.css';
		$path = $plugin_dir . $rel;
		if ( ! is_readable( $path ) ) {
			return;
		}

		if ( ! wp_style_is( 'wpps-cs-admin', 'registered' ) ) {
			wp_register_style(
				'wpps-cs-admin',
				$plugin_url . $rel,
				[ 'wp-admin' ],
				(string) filemtime( $path )
			);
		}
		wp_enqueue_style( 'wpps-cs-admin' );
	}

	private function getResolver(): User_Scheme_Resolver {
		if ( $this->resolver === null ) {
			$this->resolver = new User_Scheme_Resolver();
		}

		return $this->resolver;
	}

	private function getCssGenerator(): CSS_Generator {
		if ( $this->css_generator === null ) {
			$this->css_generator = new CSS_Generator();
		}

		return $this->css_generator;
	}
}
