<?php
/**
 * Accordion widget render layer.
 *
 * Shortcode: [rsmspark_accordion]
 * Attributes: items (JSON array of {title, content})
 *
 * @package Rsmspark_Content_Widgets
 */

defined( 'ABSPATH' ) || exit;

/**
 * Rsmspark_Content_Widgets_Widget_Accordion
 *
 * Refactored in compat branch - Phase 1
 */
class Rsmspark_Content_Widgets_Widget_Accordion {

	const REGISTRY_ID = 'accordion';

	/**
	 * @var bool
	 */
	private static $so_shell_hooks_registered = false;

	/**
	 * @var bool
	 */
	private static $rendered_on_request = false;

	/**
	 * @var bool
	 */
	private static $printed_shell_reset = false;

	/**
	 * @return void
	 */
	public static function register() {
		Rsmspark_Content_Widgets_Shortcodes::add(
			Rsmspark_Content_Widgets_Registry::shortcode_tag( self::REGISTRY_ID ),
			array( __CLASS__, 'shortcode' ),
			self::REGISTRY_ID
		);

		Rsmspark_Content_Widgets_Blocks::add(
			'accordion',
			array(
				'api_version'     => 3,
				'title'           => __( 'RSM Accordion', 'rsm-content-widgets' ),
				'description'     => __( 'Collapsible content sections.', 'rsm-content-widgets' ),
				'category'        => Rsmspark_Content_Widgets_Blocks::BLOCK_CATEGORY,
				'icon'            => 'list-view',
				'keywords'        => array( 'accordion', 'faq', 'collapse', 'rsm' ),
				'supports'        => array( 'html' => false ),
				'attributes'      => self::block_attributes(),
				'render_callback' => array( __CLASS__, 'render_block' ),
			)
		);
	}

	/**
	 * @return array<string, array<string, mixed>>
	 */
	public static function block_attributes() {
		$attrs = array(
			'items' => array(
				'type'    => 'array',
				'default' => self::default_items(),
			),
			'faq_mode' => array(
				'type'    => 'boolean',
				'default' => false,
			),
		);

		foreach ( self::color_defaults() as $key => $default ) {
			$attrs[ $key ] = array(
				'type'    => 'string',
				'default' => $default,
			);
		}

		foreach ( self::border_defaults() as $key => $default ) {
			if ( is_bool( $default ) ) {
				$attrs[ $key ] = array(
					'type'    => 'boolean',
					'default' => $default,
				);
				continue;
			}

			if ( is_int( $default ) ) {
				$attrs[ $key ] = array(
					'type'    => 'number',
					'default' => $default,
				);
				continue;
			}

			$attrs[ $key ] = array(
				'type'    => 'string',
				'default' => $default,
			);
		}

		return $attrs;
	}

	/**
	 * @return array<string, string>
	 */
	public static function color_defaults() {
		return array(
			'item_bg'              => '',
			'trigger_bg'           => '',
			'trigger_color'        => '',
			'trigger_bg_hover'     => '',
			'trigger_color_hover'  => '',
			'trigger_bg_active'    => '',
			'trigger_color_active' => '',
			'panel_bg'             => '',
			'panel_color'          => '',
		);
	}

	/**
	 * @return array<string, bool|int|string>
	 */
	public static function border_defaults() {
		return array(
			'item_border_enable'      => false,
			'item_border_width'       => 1,
			'item_border_color'       => '#e5e7eb',
			'item_border_radius'      => 'square',
			'panel_border_enable'     => false,
			'panel_border_color'      => '#e5e7eb',
			'container_border'        => false,
			'container_border_width'  => 1,
			'container_border_color'  => '#e5e7eb',
			'container_border_radius' => 'square',
		);
	}

	/**
	 * @return array<string, bool|int|string>
	 */
	public static function appearance_defaults() {
		return array_merge( self::color_defaults(), self::border_defaults() );
	}

	/**
	 * @param array<string, mixed> $atts Shortcode attributes.
	 * @param string               $content Inner content (unused).
	 * @return string
	 */
	public static function shortcode( $atts, $content = '' ) {
		unset( $content );
		$atts = is_array( $atts ) ? $atts : array();
		return self::render( self::normalize_atts( $atts ) );
	}

	/**
	 * @param array<string, mixed> $attributes Block attributes.
	 * @return string
	 */
	public static function render_block( $attributes ) {
		$attributes = is_array( $attributes ) ? $attributes : array();
		return self::render( self::normalize_atts( $attributes ) );
	}

	/**
	 * @param array<string, mixed> $atts Raw attributes.
	 * @return array<string, mixed>
	 */
	public static function normalize_atts( array $atts ) {
		$defaults = array_merge(
			self::appearance_defaults(),
			array(
				'items' => '',
			)
		);

		$parsed = Rsmspark_Content_Widgets_Render::parse_atts( $atts, $defaults, 'rsmspark_accordion' );
		$items  = self::coerce_items( $parsed['items'] );

		$normalized = array(
			'items'      => self::sanitize_items( $items ),
			'widget_uid' => 'rsmspark-cw-accordion-' . wp_unique_id(),
			'faq_mode'   => Rsmspark_Content_Widgets_Render::boolish( $parsed['faq_mode'] ?? false ),
		);

		foreach ( self::color_defaults() as $key => $default ) {
			$normalized[ $key ] = self::sanitize_color( $parsed[ $key ] ?? $default );
		}

		$normalized['item_border_enable'] = Rsmspark_Content_Widgets_Render::boolish( $parsed['item_border_enable'] ?? false );
		$normalized['item_border_width']  = max( 1, min( 8, (int) ( $parsed['item_border_width'] ?? 1 ) ) );
		$normalized['item_border_color']  = sanitize_hex_color( (string) ( $parsed['item_border_color'] ?? '#e5e7eb' ) ) ?: '#e5e7eb';
		$item_border_radius               = sanitize_key( (string) ( $parsed['item_border_radius'] ?? 'square' ) );
		$normalized['item_border_radius'] = in_array( $item_border_radius, array( 'square', 'rounded' ), true ) ? $item_border_radius : 'square';

		$normalized['panel_border_enable'] = Rsmspark_Content_Widgets_Render::boolish( $parsed['panel_border_enable'] ?? false );
		$normalized['panel_border_color']  = sanitize_hex_color( (string) ( $parsed['panel_border_color'] ?? '#e5e7eb' ) ) ?: '#e5e7eb';

		$normalized['container_border'] = Rsmspark_Content_Widgets_Render::boolish( $parsed['container_border'] ?? false );
		$normalized['container_border_width']  = max( 1, min( 8, (int) ( $parsed['container_border_width'] ?? 1 ) ) );
		$normalized['container_border_color']  = sanitize_hex_color( (string) ( $parsed['container_border_color'] ?? '#e5e7eb' ) ) ?: '#e5e7eb';
		$container_border_radius               = sanitize_key( (string) ( $parsed['container_border_radius'] ?? 'square' ) );
		$normalized['container_border_radius'] = in_array( $container_border_radius, array( 'square', 'rounded' ), true ) ? $container_border_radius : 'square';

		return $normalized;
	}

	/**
	 * @param array<string, mixed> $instance SiteOrigin widget instance.
	 * @return array<string, mixed>
	 */
	public static function prepare_from_siteorigin_instance( array $instance ) {
		$content    = Rsmspark_Content_Widgets_Render::section_instance( $instance, 'content' );
		$appearance = Rsmspark_Content_Widgets_Render::section_instance( $instance, 'appearance' );
		$borders    = Rsmspark_Content_Widgets_Render::section_instance( $instance, 'borders' );

		return self::normalize_atts( array_merge( $content, $appearance, $borders ) );
	}

	/**
	 * @param array<string, mixed> $content SiteOrigin content section.
	 * @return array<string, mixed>
	 */
	public static function prepare_from_instance( array $content ) {
		return self::normalize_atts( $content );
	}

	/**
	 * @param mixed $items Raw items from shortcode or block.
	 * @return array<int, array{title: string, content: string}>
	 */
	public static function coerce_items( $items ) {
		if ( is_string( $items ) && '' !== $items ) {
			$items = Rsmspark_Content_Widgets_Render::parse_json_attr( $items, self::default_items() );
		}
		if ( ! is_array( $items ) ) {
			$items = self::default_items();
		}

		$clean = self::sanitize_items( $items );
		if ( empty( $clean ) ) {
			$clean = self::sanitize_items( self::default_items() );
		}

		return $clean;
	}

	/**
	 * @param array<int, mixed> $items Raw accordion items.
	 * @return array<int, array{title: string, content: string}>
	 */
	public static function sanitize_items( array $items ) {
		$clean = array();
		$used  = array();
		foreach ( $items as $index => $item ) {
			if ( ! is_array( $item ) ) {
				continue;
			}
			$title     = sanitize_text_field( (string) ( $item['title'] ?? '' ) );
			$item_type = sanitize_key( (string) ( $item['item_type'] ?? 'item' ) );
			$content   = Rsmspark_Rich_Text_Body::sanitize( $item['content'] ?? '' );

			if ( 'category' === $item_type ) {
				if ( '' === $title ) {
					continue;
				}
				$content   = '';
				$item_type = 'category';
			} else {
				$item_type = 'item';
				if ( '' === $title && '' === trim( wp_strip_all_tags( $content ) ) ) {
					continue;
				}
			}

			$slug    = Rsmspark_Content_Widgets_Render::item_hash_slug( $title, (int) $index, $used );
			$used[]  = $slug;
			$clean[] = array(
				'title'     => $title,
				'content'   => $content,
				'slug'      => $slug,
				'item_type' => $item_type,
			);
		}
		return $clean;
	}

	/**
	 * @return array<int, array{title: string, content: string}>
	 */
	public static function default_items() {
		return array(
			array(
				'title'   => __( 'First section', 'rsm-content-widgets' ),
				'content' => __( 'Content for the first section.', 'rsm-content-widgets' ),
			),
			array(
				'title'   => __( 'Second section', 'rsm-content-widgets' ),
				'content' => __( 'Content for the second section.', 'rsm-content-widgets' ),
			),
		);
	}

	/**
	 * @param mixed $value Raw color value.
	 * @return string
	 */
	private static function sanitize_color( $value ) {
		return sanitize_hex_color( (string) $value ) ?: '';
	}

	/**
	 * @param string $css_name CSS custom property suffix (without prefix).
	 * @param string $value    Hex color.
	 * @return string
	 */
	private static function color_var( $css_name, $value ) {
		$value = self::sanitize_color( $value );
		if ( '' === $value ) {
			return '';
		}

		return sprintf( '--rsmspark-cw-accordion-%s:%s;', $css_name, esc_attr( $value ) );
	}

	/**
	 * @param array<string, mixed> $args Normalized widget args.
	 * @return string
	 */
	public static function section_style_vars( array $args ) {
		$vars = Rsmspark_Content_Widgets_Render::inline_style_vars();

		foreach ( self::color_defaults() as $key => $default ) {
			$vars .= self::color_var( str_replace( '_', '-', $key ), (string) ( $args[ $key ] ?? $default ) );
		}

		if ( ! empty( $args['item_border_enable'] ) ) {
			$item_width  = max( 1, min( 8, (int) ( $args['item_border_width'] ?? 1 ) ) );
			$item_color  = sanitize_hex_color( (string) ( $args['item_border_color'] ?? '#e5e7eb' ) ) ?: '#e5e7eb';
			$item_radius = 'rounded' === sanitize_key( (string) ( $args['item_border_radius'] ?? 'square' ) )
				? 'var(--rsmspark-cw-radius,8px)'
				: '0';

			$vars .= sprintf( '--rsmspark-cw-accordion-item-border-width:%dpx;', $item_width );
			$vars .= sprintf( '--rsmspark-cw-accordion-item-border-color:%s;', esc_attr( $item_color ) );
			$vars .= sprintf( '--rsmspark-cw-accordion-item-border-radius:%s;', esc_attr( $item_radius ) );
		} else {
			$vars .= '--rsmspark-cw-accordion-item-border-width:0;--rsmspark-cw-accordion-item-border-color:transparent;--rsmspark-cw-accordion-item-border-radius:0;';
		}

		if ( ! empty( $args['panel_border_enable'] ) ) {
			$panel_color = sanitize_hex_color( (string) ( $args['panel_border_color'] ?? '#e5e7eb' ) ) ?: '#e5e7eb';
			$vars       .= '--rsmspark-cw-accordion-panel-border-width:1px;';
			$vars       .= sprintf( '--rsmspark-cw-accordion-panel-border-color:%s;', esc_attr( $panel_color ) );
		} else {
			$vars .= '--rsmspark-cw-accordion-panel-border-width:0;--rsmspark-cw-accordion-panel-border-color:transparent;';
		}

		if ( ! empty( $args['container_border'] ) ) {
			$container_width  = max( 1, min( 8, (int) ( $args['container_border_width'] ?? 1 ) ) );
			$container_color    = sanitize_hex_color( (string) ( $args['container_border_color'] ?? '#e5e7eb' ) ) ?: '#e5e7eb';
			$container_radius   = 'rounded' === sanitize_key( (string) ( $args['container_border_radius'] ?? 'square' ) )
				? 'var(--rsmspark-cw-radius,8px)'
				: '0';
			$vars              .= sprintf( '--rsmspark-cw-accordion-container-border-width:%dpx;', $container_width );
			$vars              .= sprintf( '--rsmspark-cw-accordion-container-border-color:%s;', esc_attr( $container_color ) );
			$vars              .= sprintf( '--rsmspark-cw-accordion-container-border-radius:%s;', esc_attr( $container_radius ) );
		} else {
			$vars .= '--rsmspark-cw-accordion-container-border-width:0;--rsmspark-cw-accordion-container-border-color:transparent;--rsmspark-cw-accordion-container-border-radius:0;';
		}

		return $vars;
	}

	/**
	 * Register SiteOrigin wrapper border reset hooks.
	 *
	 * @return void
	 */
	public static function register_so_shell_hooks() {
		if ( self::$so_shell_hooks_registered ) {
			return;
		}
		self::$so_shell_hooks_registered = true;

		add_filter( 'siteorigin_widgets_wrapper_classes_accordion', array( __CLASS__, 'filter_so_wrapper_classes' ), 10, 3 );
		add_action( 'siteorigin_widgets_after_widget_accordion', array( __CLASS__, 'mark_so_rendered' ), 1, 2 );
		add_action( 'wp_footer', array( __CLASS__, 'print_so_shell_border_reset' ), 9999 );
		add_action( 'admin_print_footer_scripts', array( __CLASS__, 'print_so_shell_border_reset' ), 9999 );
		add_filter( 'siteorigin_panels_widget_classes', array( __CLASS__, 'filter_panels_so_panel_classes' ), 10, 4 );
	}

	/**
	 * @param array              $instance Widget instance.
	 * @param SiteOrigin_Widget $widget    Widget.
	 * @return void
	 */
	public static function mark_so_rendered( $instance, $widget ) {
		unset( $instance, $widget );
		self::$rendered_on_request = true;
	}

	/**
	 * @return void
	 */
	public static function print_so_shell_border_reset() {
		if ( ! self::$rendered_on_request || self::$printed_shell_reset ) {
			return;
		}
		self::$printed_shell_reset = true;

		$css  = 'div.so-widget-accordion.rsmspark-cw-accordion-so-shell,div.so-widget-accordion.so-widget-accordion-base.rsmspark-cw-accordion-so-shell,div.so-widget-accordion:has([data-rsmspark-cw-accordion]){border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;box-shadow:none!important;outline:none!important;background:transparent!important;padding:0!important;margin:0!important;}';
		$css .= 'div.so-widget-accordion.rsmspark-cw-accordion-so-shell::before,div.so-widget-accordion.rsmspark-cw-accordion-so-shell::after,div.so-widget-accordion:has([data-rsmspark-cw-accordion])::before,div.so-widget-accordion:has([data-rsmspark-cw-accordion])::after{content:none!important;display:none!important;border-width:0!important;border-style:none!important;box-shadow:none!important;}';
		$css .= '.so-panel.widget_accordion,.so-panel.widget.widget_accordion,.so-panel.rsmspark-cw-accordion-so-panel{border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;box-shadow:none!important;outline:none!important;background:transparent!important;}';
		$css .= '@supports selector(:has(*)){.panel-grid-cell:has(.so-widget-accordion.rsmspark-cw-accordion-so-shell),.panel-grid-cell:has([data-rsmspark-cw-accordion]){border-width:0!important;border-style:none!important;border-color:transparent!important;box-shadow:none!important;outline:none!important;}}';

		$style_handle = 'rsmspark-cw-accordion-so-shell-border-reset';
		if ( ! wp_style_is( $style_handle, 'registered' ) ) {
			wp_register_style( $style_handle, false, array(), RSMSPARK_CONTENT_WIDGETS_VERSION );
		}
		wp_enqueue_style( $style_handle );
		wp_add_inline_style( $style_handle, $css );
		wp_print_styles( $style_handle );
	}

	/**
	 * @param string[] $classes      Panel classes.
	 * @param string   $widget_class Widget class key.
	 * @param array    $instance     Instance.
	 * @param array    $widget_info  Metadata.
	 * @return string[]
	 */
	public static function filter_panels_so_panel_classes( $classes, $widget_class, $instance, $widget_info ) {
		unset( $widget_class, $instance, $widget_info );
		if ( is_array( $classes ) && in_array( 'widget_accordion', $classes, true ) ) {
			$classes[] = 'rsmspark-cw-accordion-so-panel';
		}
		return $classes;
	}

	/**
	 * @param string[]           $classes  Wrapper classes.
	 * @param array              $instance Instance.
	 * @param SiteOrigin_Widget $widget    Widget.
	 * @return string[]
	 */
	public static function filter_so_wrapper_classes( $classes, $instance, $widget ) {
		unset( $instance, $widget );
		if ( ! is_array( $classes ) ) {
			$classes = array();
		}
		$classes[] = 'rsmspark-cw-accordion-so-shell';
		return $classes;
	}

	/**
	 * @param array<string, mixed> $args Normalized render arguments.
	 * @return array<string, mixed>
	 */
	public static function prepare_template_vars( array $args ) {
		return array(
			'items'      => $args['items'] ?? array(),
			'widget_uid' => $args['widget_uid'] ?? 'rsmspark-cw-accordion-' . wp_unique_id(),
			'style_vars' => self::section_style_vars( $args ),
			'faq_mode'   => ! empty( $args['faq_mode'] ),
		);
	}

	/**
	 * @param array<string, mixed> $args Normalized render arguments.
	 * @return string
	 */
	public static function render( array $args ) {
		if ( empty( $args['items'] ) ) {
			return '';
		}

		return Rsmspark_Content_Widgets_Render::render_template(
			self::REGISTRY_ID,
			'accordion.php',
			self::prepare_template_vars( $args )
		);
	}
}

/**
 * @param array<string, mixed> $args Widget arguments.
 * @return string
 */
function rsmspark_cw_render_accordion( array $args ) {
	return Rsmspark_Content_Widgets_Widget_Accordion::render(
		Rsmspark_Content_Widgets_Widget_Accordion::normalize_atts( $args )
	);
}
