<?php
/**
 * Built-in and custom color scheme registry.
 *
 * @package WP_PowerSuite\AdminColorCustomizer
 */

namespace WP_PowerSuite\AdminColorCustomizer;

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

class Scheme_Registry {

	private static ?self $instance = null;

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

	public static function instance(): self {
		if ( self::$instance === null ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

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

		$schemes = [
			'powersuite_blue' => [
				'id'              => 'powersuite_blue',
				'name'            => __( 'PowerSuite Blue', 'wp-powersuite' ),
				'primary'         => '#2271b1',
				'secondary'       => '#135e96',
				'accent'          => '#72aee6',
				'menu_bg'         => '#1e3a5f',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#2271b1',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#1e3a5f',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#2271b1',
				'button_text'     => '#ffffff',
				'notice'          => '#72aee6',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'woocommerce_purple' => [
				'id'              => 'woocommerce_purple',
				'name'            => __( 'WooCommerce Purple', 'wp-powersuite' ),
				'primary'         => '#7f54b3',
				'secondary'       => '#674399',
				'accent'          => '#c8b5e0',
				'menu_bg'         => '#3c2867',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#7f54b3',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#3c2867',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#7f54b3',
				'button_text'     => '#ffffff',
				'notice'          => '#c8b5e0',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'agency_dark' => [
				'id'              => 'agency_dark',
				'name'            => __( 'Agency Dark', 'wp-powersuite' ),
				'primary'         => '#00b4d8',
				'secondary'       => '#0096c7',
				'accent'          => '#90e0ef',
				'menu_bg'         => '#0d1117',
				'menu_text'       => '#e6edf3',
				'menu_hover_bg'   => '#161b22',
				'menu_hover_text' => '#58a6ff',
				'toolbar_bg'      => '#010409',
				'toolbar_text'    => '#e6edf3',
				'button_bg'       => '#238636',
				'button_text'     => '#ffffff',
				'notice'          => '#58a6ff',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'clean_light' => [
				'id'              => 'clean_light',
				'name'            => __( 'Clean Light', 'wp-powersuite' ),
				'primary'         => '#3858e9',
				'secondary'       => '#2c4bdb',
				'accent'          => '#8c8f94',
				'menu_bg'         => '#ffffff',
				'menu_text'       => '#1d2327',
				'menu_hover_bg'   => '#f0f0f1',
				'menu_hover_text' => '#3858e9',
				'toolbar_bg'      => '#ffffff',
				'toolbar_text'    => '#1d2327',
				'button_bg'       => '#3858e9',
				'button_text'     => '#ffffff',
				'notice'          => '#3858e9',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'staging_warning' => [
				'id'              => 'staging_warning',
				'name'            => __( 'Staging Warning', 'wp-powersuite' ),
				'primary'         => '#d63638',
				'secondary'       => '#b32d2e',
				'accent'          => '#f0b849',
				'menu_bg'         => '#5c2b0a',
				'menu_text'       => '#fff8e5',
				'menu_hover_bg'   => '#d63638',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#8a4b08',
				'toolbar_text'    => '#fff8e5',
				'button_bg'       => '#d63638',
				'button_text'     => '#ffffff',
				'notice'          => '#f0b849',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'development_green' => [
				'id'              => 'development_green',
				'name'            => __( 'Development Green', 'wp-powersuite' ),
				'primary'         => '#00a32a',
				'secondary'       => '#008a20',
				'accent'          => '#68de7c',
				'menu_bg'         => '#0b3d1a',
				'menu_text'       => '#ecfdf0',
				'menu_hover_bg'   => '#00a32a',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#0b3d1a',
				'toolbar_text'    => '#ecfdf0',
				'button_bg'       => '#00a32a',
				'button_text'     => '#ffffff',
				'notice'          => '#68de7c',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_modern' => [
				'id'              => 'wp_modern',
				'name'            => __( 'WordPress Modern', 'wp-powersuite' ),
				'primary'         => '#3858e9',
				'secondary'       => '#2145e6',
				'accent'          => '#7585b5',
				'menu_bg'         => '#1e1e1e',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#3858e9',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#1e1e1e',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#3858e9',
				'button_text'     => '#ffffff',
				'notice'          => '#3858e9',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_light' => [
				'id'              => 'wp_light',
				'name'            => __( 'WordPress Light', 'wp-powersuite' ),
				'primary'         => '#04a4cc',
				'secondary'       => '#0387a9',
				'accent'          => '#9ad6e6',
				'menu_bg'         => '#ffffff',
				'menu_text'       => '#1d2327',
				'menu_hover_bg'   => '#f0f0f1',
				'menu_hover_text' => '#04a4cc',
				'toolbar_bg'      => '#ffffff',
				'toolbar_text'    => '#1d2327',
				'button_bg'       => '#04a4cc',
				'button_text'     => '#ffffff',
				'notice'          => '#04a4cc',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_classic_blue' => [
				'id'              => 'wp_classic_blue',
				'name'            => __( 'WordPress Classic Blue', 'wp-powersuite' ),
				'primary'         => '#096484',
				'secondary'       => '#07526c',
				'accent'          => '#52accc',
				'menu_bg'         => '#52accc',
				'menu_text'       => '#ffffff',
				'menu_icon'       => '#ffffff',
				'menu_hover_bg'   => '#096484',
				'menu_hover_text' => '#ffffff',
				'menu_hover_icon' => '#ffffff',
				'menu_current_bg' => '#096484',
				'menu_current_text' => '#ffffff',
				'menu_current_icon' => '#ffffff',
				'toolbar_bg'      => '#4796b3',
				'toolbar_text'    => '#ffffff',
				'adminbar_icon'   => '#ffffff',
				'button_bg'       => '#096484',
				'button_text'     => '#ffffff',
				'button_border'   => '#07526c',
				'notice'          => '#52accc',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_midnight' => [
				'id'              => 'wp_midnight',
				'name'            => __( 'WordPress Midnight', 'wp-powersuite' ),
				'primary'         => '#e14d43',
				'secondary'       => '#c0392b',
				'accent'          => '#f86368',
				'menu_bg'         => '#363b3f',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#e14d43',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#26292c',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#e14d43',
				'button_text'     => '#ffffff',
				'notice'          => '#f86368',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_sunrise' => [
				'id'              => 'wp_sunrise',
				'name'            => __( 'WordPress Sunrise', 'wp-powersuite' ),
				'primary'         => '#dd823b',
				'secondary'       => '#c56c28',
				'accent'          => '#f7cfae',
				'menu_bg'         => '#cf4944',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#dd823b',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#b43c38',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#dd823b',
				'button_text'     => '#ffffff',
				'notice'          => '#f7cfae',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_ectoplasm' => [
				'id'              => 'wp_ectoplasm',
				'name'            => __( 'WordPress Ectoplasm', 'wp-powersuite' ),
				'primary'         => '#a3b745',
				'secondary'       => '#839237',
				'accent'          => '#d3e29a',
				'menu_bg'         => '#523f6d',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#a3b745',
				'menu_hover_text' => '#1d2327',
				'toolbar_bg'      => '#413256',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#a3b745',
				'button_text'     => '#1d2327',
				'notice'          => '#d3e29a',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_ocean' => [
				'id'              => 'wp_ocean',
				'name'            => __( 'WordPress Ocean', 'wp-powersuite' ),
				'primary'         => '#9ebaa0',
				'secondary'       => '#7e9982',
				'accent'          => '#c6d8c9',
				'menu_bg'         => '#738e96',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#9ebaa0',
				'menu_hover_text' => '#1d2327',
				'toolbar_bg'      => '#627c83',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#9ebaa0',
				'button_text'     => '#1d2327',
				'notice'          => '#c6d8c9',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'wp_coffee' => [
				'id'              => 'wp_coffee',
				'name'            => __( 'WordPress Coffee', 'wp-powersuite' ),
				'primary'         => '#c7a589',
				'secondary'       => '#a68467',
				'accent'          => '#e2d3c5',
				'menu_bg'         => '#59524c',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#c7a589',
				'menu_hover_text' => '#1d2327',
				'toolbar_bg'      => '#46403c',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#c7a589',
				'button_text'     => '#1d2327',
				'notice'          => '#e2d3c5',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'slack_aubergine' => [
				'id'              => 'slack_aubergine',
				'name'            => __( 'Slack Aubergine', 'wp-powersuite' ),
				'primary'         => '#611f69',
				'secondary'       => '#4a154b',
				'accent'          => '#ecb22e',
				'menu_bg'         => '#4a154b',
				'menu_text'       => '#ffffff',
				'menu_hover_bg'   => '#611f69',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#350d36',
				'toolbar_text'    => '#ffffff',
				'button_bg'       => '#611f69',
				'button_text'     => '#ffffff',
				'notice'          => '#ecb22e',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'notion_light' => [
				'id'              => 'notion_light',
				'name'            => __( 'Notion Light', 'wp-powersuite' ),
				'primary'         => '#2f3437',
				'secondary'       => '#37352f',
				'accent'          => '#787774',
				'menu_bg'         => '#ffffff',
				'menu_text'       => '#37352f',
				'menu_hover_bg'   => '#f1f1ef',
				'menu_hover_text' => '#2f3437',
				'toolbar_bg'      => '#ffffff',
				'toolbar_text'    => '#37352f',
				'button_bg'       => '#2f3437',
				'button_text'     => '#ffffff',
				'notice'          => '#787774',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'github_dark' => [
				'id'              => 'github_dark',
				'name'            => __( 'GitHub Dark', 'wp-powersuite' ),
				'primary'         => '#238636',
				'secondary'       => '#1f6f2e',
				'accent'          => '#58a6ff',
				'menu_bg'         => '#0d1117',
				'menu_text'       => '#e6edf3',
				'menu_hover_bg'   => '#161b22',
				'menu_hover_text' => '#58a6ff',
				'toolbar_bg'      => '#010409',
				'toolbar_text'    => '#e6edf3',
				'button_bg'       => '#238636',
				'button_text'     => '#ffffff',
				'notice'          => '#58a6ff',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'sunset_coral' => [
				'id'              => 'sunset_coral',
				'name'            => __( 'Sunset Coral', 'wp-powersuite' ),
				'primary'         => '#ff6b6b',
				'secondary'       => '#ee5253',
				'accent'          => '#ffd093',
				'menu_bg'         => '#2d1b2e',
				'menu_text'       => '#fff5f5',
				'menu_hover_bg'   => '#ff6b6b',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#1f1220',
				'toolbar_text'    => '#fff5f5',
				'button_bg'       => '#ff6b6b',
				'button_text'     => '#ffffff',
				'notice'          => '#ffd093',
				'custom_css'      => '',
				'built_in'        => true,
			],
			'slate_pro' => [
				'id'              => 'slate_pro',
				'name'            => __( 'Slate Pro', 'wp-powersuite' ),
				'primary'         => '#334155',
				'secondary'       => '#1e293b',
				'accent'          => '#64748b',
				'menu_bg'         => '#0f172a',
				'menu_text'       => '#e2e8f0',
				'menu_hover_bg'   => '#334155',
				'menu_hover_text' => '#ffffff',
				'toolbar_bg'      => '#0f172a',
				'toolbar_text'    => '#e2e8f0',
				'button_bg'       => '#334155',
				'button_text'     => '#ffffff',
				'notice'          => '#64748b',
				'custom_css'      => '',
				'built_in'        => true,
			],
		];

		$this->built_in_cache = apply_filters( 'wpps_admin_color_customizer_schemes', $schemes );

		return $this->built_in_cache;
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, array<string, mixed>>
	 */
	public function get_all_schemes( array $settings ): array {
		$built_in = $this->get_built_in_schemes();
		$custom   = is_array( $settings['custom_schemes'] ?? null ) ? $settings['custom_schemes'] : [];

		return array_merge( $built_in, $custom );
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return list<string>
	 */
	public function get_all_scheme_ids( array $settings ): array {
		return array_keys( $this->get_all_schemes( $settings ) );
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>|null
	 */
	public function get_scheme( string $scheme_id, array $settings ): ?array {
		$scheme_id = sanitize_key( $scheme_id );
		if ( $scheme_id === '' ) {
			return null;
		}

		$all = $this->get_all_schemes( $settings );

		return $all[ $scheme_id ] ?? null;
	}

	/**
	 * @param array<string, mixed> $scheme
	 * @return array<string, mixed>|null
	 */
	public function sanitize_scheme( array $scheme, string $context = 'save' ): ?array {
		$id = isset( $scheme['id'] ) ? sanitize_key( (string) $scheme['id'] ) : '';
		if ( $id === '' || ! preg_match( '/^[a-z0-9_]{1,64}$/', $id ) ) {
			return null;
		}

		if ( ! empty( $scheme['built_in'] ) ) {
			return null;
		}

		$color_keys = [
			'primary',
			'secondary',
			'accent',
			'menu_bg',
			'menu_text',
			'menu_hover_bg',
			'menu_hover_text',
			'toolbar_bg',
			'toolbar_text',
			'button_bg',
			'button_text',
			'notice',
		];

		$sanitized = [
			'id'       => $id,
			'name'     => sanitize_text_field( (string) ( $scheme['name'] ?? $id ) ),
			'built_in' => false,
		];

		if ( $sanitized['name'] === '' ) {
			return null;
		}

		foreach ( $color_keys as $key ) {
			$color = self::sanitize_hex_color( $scheme[ $key ] ?? '' );
			if ( $color === null ) {
				return null;
			}
			$sanitized[ $key ] = $color;
		}

		$sanitized['custom_css'] = '';
		if ( ! empty( $scheme['custom_css'] ) && is_string( $scheme['custom_css'] ) && $context !== 'import' ) {
			$sanitized['custom_css'] = Settings::sanitize_custom_css( $scheme['custom_css'] );
		}

		return $sanitized;
	}

	public static function sanitize_hex_color( mixed $color ): ?string {
		if ( ! is_string( $color ) ) {
			return null;
		}

		$color = trim( $color );
		if ( ! preg_match( '/^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/', $color ) ) {
			return null;
		}

		if ( strlen( $color ) === 4 ) {
			$color = '#' . $color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3];
		}

		return strtolower( $color );
	}

	/**
	 * Stylesheet URL registered for a scheme as the core `colors` href.
	 *
	 * WordPress sets the core `colors` stylesheet href to this URL for the
	 * active scheme (wp_style_loader_src), so it must be a real, fast, cacheable
	 * CSS file — NOT an admin-ajax endpoint (which would boot WordPress on every
	 * admin page). We generate a static file per scheme (cache-busted by a hash
	 * of its colors in the filename) so the scheme applies natively everywhere:
	 * the module's own page, the profile color picker, and its live preview.
	 */
	public function get_scheme_stylesheet_url( string $scheme_id ): string {
		$scheme_id = sanitize_key( $scheme_id );
		if ( $scheme_id === '' ) {
			return '';
		}

		$settings = Settings::get_effective_settings();
		$scheme   = $this->get_scheme( $scheme_id, $settings );

		if ( is_array( $scheme ) ) {
			$url = $this->ensure_scheme_stylesheet_file( $scheme_id, $scheme, $settings );
			if ( $url !== '' ) {
				return $url;
			}
		}

		// Fallback (e.g. unwritable uploads dir): serve via admin-ajax so colors
		// still work, accepting the per-page cost only when files cannot be cached.
		return add_query_arg(
			[
				'action'   => 'wpps_acc_scheme_css',
				'scheme'   => $scheme_id,
				'_wpnonce' => wp_create_nonce( 'wpps_acc_scheme_css_' . $scheme_id ),
			],
			admin_url( 'admin-ajax.php' )
		);
	}

	/**
	 * Generate (once) and return the URL of a cached static stylesheet for a
	 * scheme. The hash in the filename busts the cache automatically whenever
	 * the scheme colors or the generator change.
	 *
	 * @param array<string, mixed> $scheme
	 * @param array<string, mixed> $settings
	 */
	private function ensure_scheme_stylesheet_file( string $scheme_id, array $scheme, array $settings ): string {
		$upload = wp_upload_dir();
		if ( ! empty( $upload['error'] ) || empty( $upload['basedir'] ) || empty( $upload['baseurl'] ) ) {
			return '';
		}

		$hash = substr( md5( (string) wp_json_encode( $scheme ) . '|' . Settings::VERSION ), 0, 10 );
		$dir  = trailingslashit( $upload['basedir'] ) . 'wp-powersuite/admin-colors';
		$file = sprintf( 'scheme-%s-%s.css', $scheme_id, $hash );
		$path = $dir . '/' . $file;
		$url  = trailingslashit( $upload['baseurl'] ) . 'wp-powersuite/admin-colors/' . $file;

		if ( ! file_exists( $path ) ) {
			if ( ! wp_mkdir_p( $dir ) ) {
				return '';
			}

			foreach ( (array) glob( $dir . '/scheme-' . $scheme_id . '-*.css' ) as $stale ) {
				if ( $stale !== $path ) {
					@unlink( $stale ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
				}
			}

			$css = ( new CSS_Generator() )->generate( $scheme, $settings, 'admin', false );
			if ( file_put_contents( $path, $css ) === false ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
				return '';
			}
		}

		return set_url_scheme( $url );
	}

	/**
	 * @return list<string>
	 */
	public function get_profile_registerable_scheme_ids( array $settings ): array {
		$built_in = array_keys( $this->get_built_in_schemes() );
		$custom   = is_array( $settings['custom_schemes'] ?? null ) ? array_keys( $settings['custom_schemes'] ) : [];

		return array_values( array_unique( array_merge( $built_in, $custom ) ) );
	}

	/**
	 * Register PowerSuite schemes with WordPress admin color picker API.
	 *
	 * @param array<string, mixed> $settings
	 */
	public function register_wp_admin_schemes( array $settings ): void {
		if ( ! function_exists( 'wp_admin_css_color' ) ) {
			return;
		}

		$defaults = Settings::get_accessible_defaults();
		$schemes  = $this->get_all_schemes( $settings );

		foreach ( $this->get_profile_registerable_scheme_ids( $settings ) as $scheme_id ) {
			if ( ! isset( $schemes[ $scheme_id ] ) || ! is_array( $schemes[ $scheme_id ] ) ) {
				continue;
			}

			$scheme = $schemes[ $scheme_id ];
			$colors = [
				self::sanitize_hex_color( $scheme['menu_bg'] ?? $defaults['menu_bg'] ) ?? $defaults['menu_bg'],
				self::sanitize_hex_color( $scheme['primary'] ?? $defaults['primary'] ) ?? $defaults['primary'],
				self::sanitize_hex_color( $scheme['secondary'] ?? $defaults['secondary'] ) ?? $defaults['secondary'],
				self::sanitize_hex_color( $scheme['accent'] ?? $defaults['accent'] ) ?? $defaults['accent'],
			];

			wp_admin_css_color(
				$scheme_id,
				(string) ( $scheme['name'] ?? $scheme_id ),
				$this->get_scheme_stylesheet_url( $scheme_id ),
				$colors,
				[
					'base'    => self::sanitize_hex_color( $scheme['menu_text'] ?? $defaults['menu_text'] ) ?? $defaults['menu_text'],
					'focus'   => self::sanitize_hex_color( $scheme['menu_hover_text'] ?? $defaults['menu_hover_text'] ) ?? $defaults['menu_hover_text'],
					'current' => self::sanitize_hex_color( $scheme['menu_hover_bg'] ?? $defaults['menu_hover_bg'] ) ?? $defaults['menu_hover_bg'],
				]
			);
		}

		$this->prune_non_powersuite_schemes( $settings );
	}

	/**
	 * Remove WordPress' native color schemes from the picker so only working
	 * PowerSuite schemes are shown. When this module manages admin colors the
	 * native schemes are overridden and would never apply, and several of them
	 * are duplicated by PowerSuite's own "WordPress …" presets — so showing them
	 * is confusing. Safe because the user's admin_color is always resolved to a
	 * registered PowerSuite scheme (so core never falls back to a removed one).
	 *
	 * @param array<string, mixed> $settings
	 */
	private function prune_non_powersuite_schemes( array $settings ): void {
		global $_wp_admin_css_colors;

		if ( ! is_array( $_wp_admin_css_colors ) ) {
			return;
		}

		$ours = $this->get_profile_registerable_scheme_ids( $settings );
		if ( empty( $ours ) ) {
			return;
		}

		foreach ( array_keys( $_wp_admin_css_colors ) as $registered_id ) {
			if ( ! in_array( (string) $registered_id, $ours, true ) ) {
				unset( $_wp_admin_css_colors[ $registered_id ] );
			}
		}
	}
}
