<?php
/**
 * RSM Editor class registry and profile definitions.
 *
 * @package Rsmspark_Editor
 */

defined( 'ABSPATH' ) || exit;

/**
 * Rsmspark_Rich_Text_Registry
 */
final class Rsmspark_Rich_Text_Registry {

	public const PROFILE_HEADLINE = 'headline';
	public const PROFILE_BODY     = 'body';
	public const PROFILE_MINIMAL  = 'minimal';

	/**
	 * @return string[]
	 */
	public static function profiles() {
		return array(
			self::PROFILE_HEADLINE,
			self::PROFILE_BODY,
			self::PROFILE_MINIMAL,
		);
	}

	/**
	 * @param string $profile Profile key.
	 * @return bool
	 */
	public static function is_valid_profile( $profile ) {
		return in_array( sanitize_key( (string) $profile ), self::profiles(), true );
	}

	/**
	 * @param string $profile Profile key.
	 * @return string[]
	 */
	public static function allowed_classes( $profile ) {
		$profile = sanitize_key( (string) $profile );
		$classes = array();

		if ( self::PROFILE_HEADLINE === $profile || self::PROFILE_BODY === $profile || self::PROFILE_MINIMAL === $profile ) {
			$classes = array_merge( $classes, self::size_classes(), self::color_classes(), self::effect_classes() );
		}

		if ( self::PROFILE_BODY === $profile ) {
			$classes = array_merge( $classes, self::list_style_classes(), self::list_marker_color_classes(), array( 'rsmspark-rt-section-title' ) );
		}

		if ( self::PROFILE_MINIMAL === $profile ) {
			$classes = array_intersect(
				$classes,
				array_merge(
					array( 'rsmspark-rt-size-body', 'rsmspark-rt-size-lead' ),
					self::color_classes()
				)
			);
		}

		$classes = array_values( array_unique( array_filter( $classes ) ) );

		/**
		 * Filter allowed rich-text classes for a profile.
		 *
		 * @param string[] $classes Class tokens without dot prefix.
		 * @param string   $profile Profile key.
		 */
		return apply_filters( 'rsmspark_rich_text_allowed_classes', $classes, $profile );
	}

	/**
	 * Preset text sizes — px values are the editor reference at a 16px root.
	 *
	 * @return array<int, array{label:string,class:string,px:int,note:string}>
	 */
	public static function size_presets() {
		return array(
			array(
				'label' => __( 'Eyebrow', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-eyebrow',
				'px'    => 12,
				'note'  => __( 'uppercase label', 'rsm-content-widgets' ),
			),
			array(
				'label' => __( 'Body', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-body',
				'px'    => 16,
				'note'  => '',
			),
			array(
				'label' => __( 'Lead', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-lead',
				'px'    => 18,
				'note'  => __( 'intro text', 'rsm-content-widgets' ),
			),
			array(
				'label' => __( 'Title', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-title',
				'px'    => 24,
				'note'  => __( 'bold', 'rsm-content-widgets' ),
			),
			array(
				'label' => __( 'Display', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-display',
				'px'    => 36,
				'note'  => __( 'bold', 'rsm-content-widgets' ),
			),
			array(
				'label' => __( 'Hero', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-hero',
				'px'    => 44,
				'note'  => __( 'bold', 'rsm-content-widgets' ),
			),
			array(
				'label' => __( 'Jumbo', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-size-jumbo',
				'px'    => 52,
				'note'  => __( 'bold', 'rsm-content-widgets' ),
			),
		);
	}

	/**
	 * Preset text colors with human-readable names and hex values.
	 *
	 * @return array<int, array{label:string,class:string,hex:string}>
	 */
	public static function color_presets() {
		return array(
			array(
				'label' => __( 'Near black', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-default',
				'hex'   => '#0f172a',
			),
			array(
				'label' => __( 'Gray', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-muted',
				'hex'   => '#64748b',
			),
			array(
				'label' => __( 'Orange (brand)', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-accent',
				'hex'   => '#ff6b35',
			),
			array(
				'label' => __( 'Blue', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-primary',
				'hex'   => '#2563eb',
			),
			array(
				'label' => __( 'White', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-inverse',
				'hex'   => '#ffffff',
			),
			array(
				'label' => __( 'Green', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-success',
				'hex'   => '#16a34a',
			),
			array(
				'label' => __( 'Red', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-danger',
				'hex'   => '#dc2626',
			),
			array(
				'label' => __( 'Amber', 'rsm-content-widgets' ),
				'class' => 'rsmspark-rt-color-warning',
				'hex'   => '#ca8a04',
			),
		);
	}

	/**
	 * Allowed custom font-size range (px).
	 *
	 * @return array{min:int,max:int}
	 */
	public static function custom_size_limits() {
		return array(
			'min' => 8,
			'max' => 120,
		);
	}

	/**
	 * @return string[]
	 */
	public static function size_classes() {
		return array_column( self::size_presets(), 'class' );
	}

	/**
	 * @return string[]
	 */
	public static function color_classes() {
		$classes = array_column( self::color_presets(), 'class' );
		$classes[] = 'rsmspark-rt-color-inherit';

		return array_values( array_unique( $classes ) );
	}

	/**
	 * @return string[]
	 */
	public static function effect_classes() {
		return array(
			'rsmspark-rt-gradient-brand',
			'rsmspark-rt-uppercase',
			'rsmspark-rt-normal-case',
		);
	}

	/**
	 * @return string[]
	 */
	public static function list_style_classes() {
		return array(
			'rsmspark-rt-list',
			'rsmspark-rt-list--bullet',
			'rsmspark-rt-list--check',
			'rsmspark-rt-list--x',
			'rsmspark-rt-list--star',
			'rsmspark-rt-list--square',
			'rsmspark-rt-list--none',
		);
	}

	/**
	 * @return string[]
	 */
	public static function list_marker_color_classes() {
		return array(
			'rsmspark-rt-list-marker-accent',
			'rsmspark-rt-list-marker-primary',
			'rsmspark-rt-list-marker-success',
			'rsmspark-rt-list-marker-danger',
			'rsmspark-rt-list-marker-warning',
			'rsmspark-rt-list-marker-muted',
			'rsmspark-rt-list-marker-inverse',
		);
	}

	/**
	 * Marker preset class => hex (matches rsm-editor.css).
	 *
	 * @return array<string, string>
	 */
	public static function list_marker_color_map() {
		return array(
			'rsmspark-rt-list-marker-accent'   => '#ff6b35',
			'rsmspark-rt-list-marker-primary'  => '#2563eb',
			'rsmspark-rt-list-marker-success'  => '#16a34a',
			'rsmspark-rt-list-marker-danger'   => '#dc2626',
			'rsmspark-rt-list-marker-warning'  => '#ca8a04',
			'rsmspark-rt-list-marker-muted'    => '#64748b',
			'rsmspark-rt-list-marker-inverse'  => '#ffffff',
		);
	}

	/**
	 * List style modifiers (--check, --bullet, etc.) excluding the base token.
	 *
	 * @return string[]
	 */
	public static function list_style_modifier_classes() {
		return array_values(
			array_filter(
				self::list_style_classes(),
				static function ( $class ) {
					return false !== strpos( $class, '--' );
				}
			)
		);
	}

	/**
	 * @param string $profile Profile key.
	 * @return array<string, array<string, bool>>
	 */
	public static function allowed_tags( $profile ) {
		$profile = sanitize_key( (string) $profile );
		if ( ! self::is_valid_profile( $profile ) ) {
			return array();
		}

		$tags = array(
			'br'     => array(),
			'strong' => array(),
			'b'      => array(),
			'em'     => array(),
			'i'      => array(),
			'span'   => array(
				'class' => true,
				'style' => true,
			),
			'a'      => array(
				'href'   => true,
				'title'  => true,
				'target' => true,
				'rel'    => true,
			),
		);

		if ( self::PROFILE_BODY === $profile ) {
			$tags['p'] = array(
				'class' => true,
			);
			$tags['ul'] = array(
				'class' => true,
				'style' => true,
			);
			$tags['ol'] = array(
				'class' => true,
				'style' => true,
			);
			$tags['li'] = array();
			$tags['h3'] = array(
				'class' => true,
			);
		}

		/**
		 * Filter allowed HTML tags for a rich-text profile.
		 *
		 * @param array<string, array<string, bool>> $tags    Tag allowlist.
		 * @param string                             $profile Profile key.
		 */
		return apply_filters( 'rsmspark_rich_text_allowed_tags', $tags, $profile );
	}

	/**
	 * TinyMCE toolbar1 button list for a profile.
	 *
	 * @param string $profile Profile key.
	 * @return string
	 */
	public static function toolbar1( $profile ) {
		$profile = sanitize_key( (string) $profile );

		$prefix = array( 'bold', 'italic', 'link' );
		if ( self::toolbar_media_enabled() ) {
			$prefix[] = 'rsm_rt_media';
		}
		$prefix[] = '|';

		if ( self::PROFILE_HEADLINE === $profile ) {
			$buttons = array_merge(
				$prefix,
				array(
					'rsm_rt_size',
					'rsm_rt_color',
					'rsm_rt_gradient',
					'rsm_rt_highlight',
					'rsm_rt_font',
				)
			);
		} elseif ( self::PROFILE_BODY === $profile ) {
			$buttons = array_merge(
				$prefix,
				array(
					'rsm_rt_size',
					'rsm_rt_color',
					'rsm_rt_highlight',
					'rsm_rt_font',
					'rsm_rt_section',
					'|',
					'rsm_rt_list',
					'rsm_rt_list_color',
				)
			);
		} else {
			$buttons = array_merge(
				$prefix,
				array(
					'rsm_rt_size',
				)
			);
		}

		/**
		 * Filter TinyMCE toolbar buttons for a profile.
		 *
		 * @param string[] $buttons Button ids.
		 * @param string   $profile Profile key.
		 */
		$buttons = apply_filters( 'rsmspark_rich_text_toolbar_buttons', $buttons, $profile );

		return implode( ',', array_map( 'strval', $buttons ) );
	}

	/**
	 * @return bool
	 */
	public static function toolbar_media_enabled() {
		if ( ! class_exists( 'Rsmspark_Content_Widgets_Settings', false ) ) {
			return false;
		}

		return Rsmspark_Content_Widgets_Settings::editor_media_row_enabled();
	}

	/**
	 * Profile config keyed for TinyMCE init / JS bootstrap.
	 *
	 * @return array<string, array<string, mixed>>
	 */
	public static function js_profiles() {
		return array(
			self::PROFILE_HEADLINE => self::js_config( self::PROFILE_HEADLINE ),
			self::PROFILE_BODY     => self::js_config( self::PROFILE_BODY ),
			self::PROFILE_MINIMAL  => self::js_config( self::PROFILE_MINIMAL ),
		);
	}

	/**
	 * TinyMCE init settings merged per editor instance.
	 *
	 * @param string $profile Profile key.
	 * @return array<string, mixed>
	 */
	public static function tinymce_settings( $profile ) {
		$profile = sanitize_key( (string) $profile );
		if ( ! self::is_valid_profile( $profile ) ) {
			return array();
		}

		$preview_css = Rsmspark_Rich_Text_Assets::stylesheet_url() . ',' . Rsmspark_Rich_Text_Assets::preview_stylesheet_url();

		$settings = array(
			'rsm_rt_profile'          => $profile,
			'rsm_rt_profiles'         => wp_json_encode( self::js_profiles() ),
			'toolbar1'                => self::toolbar1( $profile ),
			'toolbar2'            => '',
			'plugins'             => 'charmap,link,lists,wordpress,wplink,rsm_rich_text',
			'wpautop'             => self::PROFILE_HEADLINE !== $profile,
			'forced_root_block'   => self::PROFILE_HEADLINE === $profile ? false : 'p',
			'force_br_newlines'   => self::PROFILE_HEADLINE === $profile,
			'force_p_newlines'    => self::PROFILE_HEADLINE !== $profile,
			'paste_as_text'       => false,
			'body_class'          => 'rsmspark-rt-editor rsmspark-rt-root rsmspark-rt-profile-' . $profile,
			'content_css'         => Rsmspark_Rich_Text_Assets::preview_stylesheet_url() . ',' . Rsmspark_Rich_Text_Assets::stylesheet_url(),
			'height'              => self::PROFILE_HEADLINE === $profile ? 140 : 220,
			'resize'              => 'vertical',
			'extended_valid_elements' => 'span[class|style],a[href|title|target|rel],h3[class],ul[class|style],ol[class|style]',
			'verify_html'         => false,
		);

		/**
		 * Filter per-editor TinyMCE settings for a profile.
		 *
		 * @param array<string, mixed> $settings TinyMCE settings.
		 * @param string               $profile  Profile key.
		 */
		return apply_filters( 'rsmspark_rich_text_tinymce_settings', $settings, $profile );
	}

	/**
	 * SiteOrigin tinymce field helper.
	 *
	 * @param string $profile Profile key.
	 * @param int    $rows    Editor rows.
	 * @return array<string, mixed>
	 */
	public static function siteorigin_tinymce_field( $profile, $rows = 6 ) {
		$profile = sanitize_key( (string) $profile );
		$media_row = class_exists( 'Rsmspark_Content_Widgets_Settings', false )
			? Rsmspark_Content_Widgets_Settings::editor_media_row_enabled()
			: false;
		$use_rsm_media = class_exists( 'Rsmspark_Content_Widgets_Settings', false )
			? Rsmspark_Content_Widgets_Settings::editor_use_rsm_media_picker()
			: false;

		return array(
			'type'             => 'tinymce',
			'rows'             => max( 3, (int) $rows ),
			'media_buttons'    => $media_row || $use_rsm_media,
			'rsm_rt_profile'   => $profile,
			'editor_class'     => 'rsmspark-rt-editor rsmspark-rt-profile-' . $profile,
			'tinymce_settings' => self::tinymce_settings( $profile ),
		);
	}

	/**
	 * @param string $profile Profile key.
	 * @return array<string, mixed>
	 */
	public static function js_config( $profile ) {
		$profile = sanitize_key( (string) $profile );

		return array(
			'profile'       => $profile,
			'sizes'         => self::size_menu_items( $profile ),
			'colors'        => self::color_menu_items(),
			'fonts'         => Rsmspark_Rich_Text_Standards::font_menu_items(),
			'listStyles'          => self::list_style_menu_items(),
			'markerColorClasses'  => self::list_marker_color_classes(),
			'markerColorMap'      => self::list_marker_color_map(),
			'sizeClasses'   => self::size_classes(),
			'colorClasses'  => self::color_classes(),
			'effectClasses' => self::effect_classes(),
			'sizeLimits'    => self::custom_size_limits(),
			'i18n'          => array(
				'size'               => __( 'Text size', 'rsm-content-widgets' ),
				'color'              => __( 'Text color', 'rsm-content-widgets' ),
				'highlight'          => __( 'Highlight', 'rsm-content-widgets' ),
				'gradient'           => __( 'Gradient', 'rsm-content-widgets' ),
				'font'               => __( 'Font', 'rsm-content-widgets' ),
				'list'               => __( 'List style', 'rsm-content-widgets' ),
				'listColor'          => __( 'List marker color', 'rsm-content-widgets' ),
				'sectionTitle'       => __( 'Section title', 'rsm-content-widgets' ),
				'insertMedia'        => __( 'Insert image (RSM Media)', 'rsm-content-widgets' ),
				'customSize'         => __( 'Custom size…', 'rsm-content-widgets' ),
				'customSizeTitle'    => __( 'Custom font size', 'rsm-content-widgets' ),
				'customSizeLabel'    => __( 'Size (px)', 'rsm-content-widgets' ),
				'customSizeHelp'     => __( 'Enter 8–120. Output is saved as inline font-size.', 'rsm-content-widgets' ),
				'customColor'        => __( 'Custom color…', 'rsm-content-widgets' ),
				'customColorTitle'   => __( 'Custom text color', 'rsm-content-widgets' ),
				'customColorLabel'   => __( 'Hex color', 'rsm-content-widgets' ),
				'customColorHelp'    => __( 'Example: #7c3aed or 7c3aed', 'rsm-content-widgets' ),
				'customColorInvalid' => __( 'Enter a valid hex color (#RGB or #RRGGBB).', 'rsm-content-widgets' ),
				'customSizeInvalid'  => __( 'Enter a whole number between 8 and 120.', 'rsm-content-widgets' ),
				'customHighlight'    => __( 'Custom highlight…', 'rsm-content-widgets' ),
				'customHighlightTitle' => __( 'Custom highlight color', 'rsm-content-widgets' ),
				'customFont'         => __( 'Custom font stack…', 'rsm-content-widgets' ),
				'customFontTitle'    => __( 'Custom font family', 'rsm-content-widgets' ),
				'customFontLabel'    => __( 'Font stack', 'rsm-content-widgets' ),
				'customFontHelp'     => __( 'Example: Georgia, serif or Inter, system-ui, sans-serif', 'rsm-content-widgets' ),
				'customFontInvalid'  => __( 'Enter a valid font-family stack.', 'rsm-content-widgets' ),
			),
		);
	}

	/**
	 * @param string $profile Profile key.
	 * @return array<int, array<string, string>>
	 */
	private static function size_menu_items( $profile ) {
		return Rsmspark_Rich_Text_Standards::menu_sizes( $profile );
	}

	/**
	 * @return array<int, array<string, string>>
	 */
	private static function color_menu_items() {
		return Rsmspark_Rich_Text_Standards::menu_colors();
	}

	/**
	 * @return array<int, array<string, string>>
	 */
	private static function list_style_menu_items() {
		return array(
			array( 'label' => __( 'Bullet', 'rsm-content-widgets' ), 'class' => 'rsmspark-rt-list--bullet' ),
			array( 'label' => __( 'Check', 'rsm-content-widgets' ), 'class' => 'rsmspark-rt-list--check' ),
			array( 'label' => __( 'X', 'rsm-content-widgets' ), 'class' => 'rsmspark-rt-list--x' ),
			array( 'label' => __( 'Star', 'rsm-content-widgets' ), 'class' => 'rsmspark-rt-list--star' ),
			array( 'label' => __( 'Plain (no marker)', 'rsm-content-widgets' ), 'class' => 'rsmspark-rt-list--none' ),
		);
	}
}
