<?php
/**
 * Attr normalization for `divi_module_library_register_module_attrs` hooks in {@see DiviSupreme\Modules}.
 *
 * Module classes depend on this class — not on {@see DiviSupreme\Includes\Divi5Conversion} — so
 * conversion/migrator code stays isolated under Divi5Conversion/.
 *
 * @package DiviSupreme
 */

declare(strict_types=1);

namespace DiviSupreme\Includes;

use DiviSupreme\Includes\Divi5Conversion\ConversionAttrs;

/**
 * Delegates to ConversionAttrs for register-module merge normalization.
 */
final class ModuleRegisterAttrsNormalize {

	/**
	 * Random Image: coerce overlay toggles after merged attrs (legacy bool / string shapes).
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function random_image_overlay_toggles( array &$attrs ): void {
		ConversionAttrs::coerce_inner_desktop_toggle_on_off( $attrs, 'use_overlay', 'off' );
		ConversionAttrs::coerce_inner_desktop_toggle_on_off( $attrs, 'overlay_on_hover', 'on' );
	}

	/**
	 * Scroll Image: normalize uploads, decoration title, toggles, ranges after merge.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function scroll_image_merged( array &$attrs ): void {
		ConversionAttrs::normalize_scroll_image_merged_attrs( $attrs );
	}

	/**
	 * Perspective Image: uploads + alt/title → Advanced → Attributes (scroll-image pattern).
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function perspective_image_merged( array &$attrs ): void {
		ConversionAttrs::normalize_perspective_image_merged_attrs( $attrs );
	}

	/**
	 * Dual Heading: display types, heading tag, legacy parts_gap, range normalization.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function dual_heading_merged( array &$attrs ): void {
		ConversionAttrs::normalize_dual_heading_attrs( $attrs );
	}

	/**
	 * Card Carousel Child: ensure rich `content` uses `{ text }` under `innerContent.*.value` for Visual Builder.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function card_carousel_child_merged( array &$attrs ): void {
		ConversionAttrs::ensure_heading_link_inner_content_for_render( $attrs, 'title' );
		ConversionAttrs::ensure_heading_link_inner_content_for_render( $attrs, 'subtitle' );
		ConversionAttrs::ensure_inner_content_text_shape_for_render( $attrs, 'content' );
	}

	/**
	 * Circle Info parent: hydrate layout innerContent defaults so orbit transform styles print after D4 migration.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function circle_info_merged( array &$attrs ): void {
		ConversionAttrs::ensure_circle_info_parent_layout_inner_content_defaults( $attrs );
	}

	/**
	 * Image Hotspots Child: ensure rich `content` uses `{ text }` under `innerContent.*.value` for Visual Builder.
	 *
	 * D4→D5 migration often stores tooltip HTML as a **string** at `*.value`; VB RichText expects `*.value.text`.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function image_hotspots_child_merged( array &$attrs ): void {
		ConversionAttrs::ensure_inner_content_text_shape_for_render( $attrs, 'content' );
		self::migrate_legacy_tooltip_header_font_to_heading_font( $attrs, 'tooltip_header', 'tooltip_body' );
	}

	/**
	 * Icon List Child: ensure tooltip rich `content` uses `{ text }` under `innerContent.*.value`.
	 *
	 * D4→D5 migration often stores tooltip HTML as a string at `*.value`; `$elements->render()` with
	 * `attrSubName` `text` requires `*.value.text` or MultiView fatals on the frontend.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function icon_list_child_merged( array &$attrs ): void {
		ConversionAttrs::ensure_inner_content_text_shape_for_render( $attrs, 'content' );
	}

	/**
	 * Price List Child: rich `content` must use `{ text }` under `innerContent.*.value` for `$elements->render()`.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function price_list_child_merged( array &$attrs ): void {
		ConversionAttrs::ensure_inner_content_text_shape_for_render( $attrs, 'content' );
	}

	/**
	 * Parent Image Hotspots: move legacy `header.decoration.font` into per-level headingFont on `body`.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function image_hotspots_merged( array &$attrs ): void {
		self::migrate_legacy_tooltip_header_font_to_heading_font( $attrs, 'header', 'body' );
	}

	/**
	 * Move legacy single-level tooltip header font attrs into per-level headingFont (Text module parity).
	 *
	 * @param array<string, mixed> $attrs           Module attrs by reference.
	 * @param string               $legacy_attr_key Former header/font attribute key.
	 * @param string               $body_attr_key   Target attribute that owns headingFont + bodyFont.
	 * @return void
	 */
	public static function migrate_legacy_tooltip_header_font_to_heading_font( array &$attrs, string $legacy_attr_key, string $body_attr_key ): void {
		if ( ! isset( $attrs[ $legacy_attr_key ]['decoration']['font'] ) || ! is_array( $attrs[ $legacy_attr_key ]['decoration']['font'] ) ) {
			return;
		}

		$legacy_font = $attrs[ $legacy_attr_key ]['decoration']['font'];
		$level       = $legacy_font['font']['desktop']['value']['headingLevel'] ?? 'h1';

		if ( ! is_string( $level ) || ! preg_match( '/^h[1-6]$/', $level ) ) {
			$level = 'h1';
		}

		if ( ! isset( $attrs[ $body_attr_key ]['decoration'] ) || ! is_array( $attrs[ $body_attr_key ]['decoration'] ) ) {
			$attrs[ $body_attr_key ]['decoration'] = array();
		}

		if ( ! isset( $attrs[ $body_attr_key ]['decoration']['headingFont'] ) || ! is_array( $attrs[ $body_attr_key ]['decoration']['headingFont'] ) ) {
			$attrs[ $body_attr_key ]['decoration']['headingFont'] = array();
		}

		if ( ! isset( $attrs[ $body_attr_key ]['decoration']['headingFont'][ $level ] ) ) {
			$attrs[ $body_attr_key ]['decoration']['headingFont'][ $level ] = $legacy_font;
		}

		unset( $attrs[ $legacy_attr_key ] );
	}

	/**
	 * Typing Effect: coerce pipe / JSON string / legacy shapes to SortableList rows for Visual Builder.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function typing_effect_merged( array &$attrs ): void {
		ConversionAttrs::normalize_typing_effect_block_attrs( $attrs );
	}

	/**
	 * FAQ parent: migrate legacy toggle row color `innerContent` into `decoration.background`.
	 *
	 * @param array<string, mixed> $attrs Module attrs by reference.
	 * @return void
	 */
	public static function faq_merged( array &$attrs ): void {
		ConversionAttrs::migrate_faq_toggle_legacy_inner_content_color_into_decoration_background( $attrs );
	}

	/**
	 * FAQ child item: migrate legacy toggle row color; copy from parent FAQ when child never set its own row backgrounds.
	 *
	 * @param array<string, mixed>      $attrs         Child module attrs reference.
	 * @param array<string, mixed>|null $parent_attrs Parent `dsm/faq` attrs (optional).
	 * @return void
	 */
	public static function faq_child_merged( array &$attrs, ?array $parent_attrs = null ): void {
		ConversionAttrs::migrate_faq_toggle_legacy_inner_content_color_into_decoration_background( $attrs );

		if ( \is_array( $parent_attrs ) && array() !== $parent_attrs ) {
			ConversionAttrs::hydrate_faq_child_toggle_backgrounds_from_parent( $attrs, $parent_attrs );
		}
	}
}
