<?php
/**
 * Logo / clients grid widget render layer.
 *
 * Shortcode: [rsmspark_logo_grid]
 *
 * @package Rsmspark_Content_Widgets
 */

defined( 'ABSPATH' ) || exit;

/**
 * Rsmspark_Content_Widgets_Widget_Logo_Grid
 */
class Rsmspark_Content_Widgets_Widget_Logo_Grid {

	const REGISTRY_ID = 'logo_grid';

	/**
	 * @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(
			'logo-grid',
			array(
				'api_version'     => 3,
				'title'           => __( 'RSM Logo Grid', 'rsm-content-widgets' ),
				'description'     => __( 'Grid of client or partner logos with optional links.', 'rsm-content-widgets' ),
				'category'        => Rsmspark_Content_Widgets_Blocks::BLOCK_CATEGORY,
				'icon'            => 'images-alt2',
				'keywords'        => array( 'logo', 'clients', 'partners', 'trust', '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() {
		return array(
			'title'         => array( 'type' => 'string', 'default' => '' ),
			'title_color'   => array( 'type' => 'string', 'default' => '' ),
			'title_size'    => array( 'type' => 'number', 'default' => 0 ),
			'columns'       => array( 'type' => 'string', 'default' => '4' ),
			'border_enable'           => array( 'type' => 'boolean', 'default' => false ),
			'border_width'            => array( 'type' => 'number', 'default' => 1 ),
			'border_color'            => array( 'type' => 'string', 'default' => '#e2e8f0' ),
			'border_radius'           => array( 'type' => 'string', 'default' => 'square' ),
			'container_border'        => array( 'type' => 'boolean', 'default' => false ),
			'container_border_width'  => array( 'type' => 'number', 'default' => 1 ),
			'container_border_color'  => array( 'type' => 'string', 'default' => '#e2e8f0' ),
			'container_border_radius' => array( 'type' => 'string', 'default' => 'square' ),
			'bordered'                => array( 'type' => 'boolean', 'default' => false ),
			'items'         => array( 'type' => 'array', 'default' => self::default_items() ),
		);
	}

	/**
	 * @return array<int, array<string, mixed>>
	 */
	public static function default_items() {
		return array(
			array(
				'image'     => 0,
				'image_src' => '',
				'name'      => __( 'Client One', 'rsm-content-widgets' ),
				'url'       => '',
				'alt'       => '',
			),
			array(
				'image'     => 0,
				'image_src' => '',
				'name'      => __( 'Client Two', 'rsm-content-widgets' ),
				'url'       => '',
				'alt'       => '',
			),
			array(
				'image'     => 0,
				'image_src' => '',
				'name'      => __( 'Client Three', 'rsm-content-widgets' ),
				'url'       => '',
				'alt'       => '',
			),
			array(
				'image'     => 0,
				'image_src' => '',
				'name'      => __( 'Client Four', 'rsm-content-widgets' ),
				'url'       => '',
				'alt'       => '',
			),
		);
	}

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

	/**
	 * @param array<string, mixed> $attributes Block attributes.
	 * @param string               $content Inner content.
	 * @param WP_Block|null        $block Block instance.
	 * @return string
	 */
	public static function render_block( $attributes, $content = '', $block = null ) {
		unset( $content );
		$attributes = self::merge_block_attributes( $attributes, $block );
		return self::render( self::prepare_template_vars( self::normalize_atts( $attributes ) ) );
	}

	/**
	 * @param mixed         $attributes Render callback attributes.
	 * @param WP_Block|null $block      Block instance.
	 * @return array<string, mixed>
	 */
	public static function merge_block_attributes( $attributes, $block = null ) {
		$merged = is_array( $attributes ) ? $attributes : array();

		if ( $block instanceof WP_Block ) {
			if ( ! empty( $block->parsed_block['attrs'] ) && is_array( $block->parsed_block['attrs'] ) ) {
				$merged = array_merge( $merged, $block->parsed_block['attrs'] );
			}
			if ( ! empty( $block->attributes ) && is_array( $block->attributes ) ) {
				$merged = array_merge( $merged, $block->attributes );
			}
		}

		return $merged;
	}

	/**
	 * @param array<string, mixed> $atts Raw attributes.
	 * @return array<string, mixed>
	 */
	public static function normalize_atts( array $atts ) {
		$defaults = array(
			'title'         => '',
			'title_color'   => '',
			'title_size'    => 0,
			'columns'       => '4',
			'border_enable'           => false,
			'border_width'            => 1,
			'border_color'            => '#e2e8f0',
			'border_radius'           => 'square',
			'container_border'        => false,
			'container_border_width'  => 1,
			'container_border_color'  => '#e2e8f0',
			'container_border_radius' => 'square',
			'bordered'                => false,
			'items'         => self::default_items(),
		);

		$parsed = Rsmspark_Content_Widgets_Render::parse_atts( $atts, $defaults, 'rsmspark_logo_grid' );

		$columns = (string) $parsed['columns'];
		if ( ! in_array( $columns, array( '2', '3', '4', '5', '6' ), true ) ) {
			$columns = '4';
		}

		$border_radius = sanitize_key( (string) ( $parsed['border_radius'] ?? 'square' ) );
		if ( ! in_array( $border_radius, array( 'square', 'rounded' ), true ) ) {
			$border_radius = 'square';
		}

		$border_enable = Rsmspark_Content_Widgets_Render::boolish( $parsed['border_enable'] ?? false );
		$border_width  = max( 0, min( 8, (int) ( $parsed['border_width'] ?? 1 ) ) );
		$border_color  = sanitize_hex_color( (string) ( $parsed['border_color'] ?? '#e2e8f0' ) ) ?: '#e2e8f0';

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

		$title_size = max( 0, min( 72, (int) ( $parsed['title_size'] ?? 0 ) ) );
		$title_color = sanitize_hex_color( (string) ( $parsed['title_color'] ?? '' ) ) ?: '';

		return array(
			'title'         => sanitize_text_field( (string) $parsed['title'] ),
			'title_color'   => $title_color,
			'title_size'    => $title_size,
			'columns'       => $columns,
			'layout'        => 'grid',
			'border_enable'           => $border_enable,
			'border_width'            => $border_width,
			'border_color'            => $border_color,
			'border_radius'           => $border_radius,
			'container_border'        => $container_border,
			'container_border_width'  => $container_border_width,
			'container_border_color'  => $container_border_color,
			'container_border_radius' => $container_border_radius,
			'hover_overlay' => false,
			'grayscale'     => false,
			'items'         => self::coerce_items( $parsed['items'] ),
		);
	}

	/**
	 * @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();

		if ( ! empty( $args['title_color'] ) ) {
			$vars .= sprintf( '--rsmspark-cw-logo-title-color:%s;', esc_attr( (string) $args['title_color'] ) );
		}

		$title_size = (int) ( $args['title_size'] ?? 0 );
		if ( $title_size > 0 ) {
			$vars .= sprintf( '--rsmspark-cw-logo-title-size:%dpx;', $title_size );
		}

		$border_enable = ! empty( $args['border_enable'] );
		$border_width  = max( 0, min( 8, (int) ( $args['border_width'] ?? 1 ) ) );

		if ( $border_enable && $border_width > 0 ) {
			$border_color  = sanitize_hex_color( (string) ( $args['border_color'] ?? '#e2e8f0' ) ) ?: '#e2e8f0';
			$border_radius = 'rounded' === sanitize_key( (string) ( $args['border_radius'] ?? 'square' ) )
				? 'var(--rsmspark-cw-radius,8px)'
				: '0';

			$vars .= sprintf( '--rsmspark-cw-logo-border-width:%dpx;', $border_width );
			$vars .= sprintf( '--rsmspark-cw-logo-border-color:%s;', esc_attr( $border_color ) );
			$vars .= sprintf( '--rsmspark-cw-logo-border-radius:%s;', esc_attr( $border_radius ) );
		} else {
			$vars .= '--rsmspark-cw-logo-border-width:0;--rsmspark-cw-logo-border-color:transparent;--rsmspark-cw-logo-border-radius:0;';
		}

		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'] ?? '#e2e8f0' ) ) ?: '#e2e8f0';
			$container_radius = 'rounded' === sanitize_key( (string) ( $args['container_border_radius'] ?? 'square' ) )
				? 'var(--rsmspark-cw-radius,8px)'
				: '0';

			$vars .= sprintf( '--rsmspark-cw-logo-container-border-width:%dpx;', $container_width );
			$vars .= sprintf( '--rsmspark-cw-logo-container-border-color:%s;', esc_attr( $container_color ) );
			$vars .= sprintf( '--rsmspark-cw-logo-container-border-radius:%s;', esc_attr( $container_radius ) );
		}

		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_logo-grid', array( __CLASS__, 'filter_so_wrapper_classes' ), 10, 3 );
		add_action( 'siteorigin_widgets_after_widget_logo-grid', 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-logo-grid.rsmspark-cw-logo-grid-so-shell,div.so-widget-logo-grid.so-widget-logo-grid-base.rsmspark-cw-logo-grid-so-shell,div.so-widget-logo-grid:has([data-rsmspark-logo-grid]){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-logo-grid.rsmspark-cw-logo-grid-so-shell::before,div.so-widget-logo-grid.rsmspark-cw-logo-grid-so-shell::after,div.so-widget-logo-grid:has([data-rsmspark-logo-grid])::before,div.so-widget-logo-grid:has([data-rsmspark-logo-grid])::after{content:none!important;display:none!important;border-width:0!important;border-style:none!important;box-shadow:none!important;}';
		$css .= '.so-panel.widget_logo-grid,.so-panel.widget.widget_logo-grid,.so-panel.rsmspark-cw-logo-grid-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-logo-grid.rsmspark-cw-logo-grid-so-shell),.panel-grid-cell:has([data-rsmspark-logo-grid]){border-width:0!important;border-style:none!important;border-color:transparent!important;box-shadow:none!important;outline:none!important;}}';

		$style_handle = 'rsmspark-cw-logo-grid-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_logo-grid', $classes, true ) ) {
			$classes[] = 'rsmspark-cw-logo-grid-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-logo-grid-so-shell';
		return $classes;
	}

	/**
	 * @param mixed $items Raw items.
	 * @return array<int, array<string, mixed>>
	 */
	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 );
		return ! empty( $clean ) ? $clean : self::sanitize_items( self::default_items() );
	}

	/**
	 * @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 );
	}

	/**
	 * Merge SiteOrigin appearance + content sections.
	 *
	 * @param array<string, mixed> $instance 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' );

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

	/**
	 * @param array<int, mixed> $items Raw items.
	 * @return array<int, array<string, mixed>>
	 */
	public static function sanitize_items( array $items ) {
		$clean = array();

		foreach ( $items as $item ) {
			if ( ! is_array( $item ) ) {
				continue;
			}

			$image_url = self::item_image_url( $item );
			$name      = sanitize_text_field( (string) ( $item['name'] ?? '' ) );
			if ( '' === $image_url && '' === $name ) {
				continue;
			}

			$clean[] = array(
				'image_url' => $image_url,
				'name'      => $name,
				'url'       => esc_url_raw( Rsmspark_Content_Widgets_Render::link_url( $item['url'] ?? '' ) ),
				'alt'       => sanitize_text_field( (string) ( $item['alt'] ?? $name ) ),
			);
		}

		return $clean;
	}

	/**
	 * @param array<string, mixed> $item Logo item.
	 * @return string
	 */
	public static function item_image_url( array $item ) {
		$direct = esc_url_raw( trim( (string) ( $item['image_src'] ?? '' ) ) );
		if ( '' !== $direct ) {
			return $direct;
		}

		$image = $item['image'] ?? '';
		if ( is_array( $image ) ) {
			return Rsmspark_Content_Widgets_Render::media_url( $image, 'medium' );
		}

		if ( is_numeric( $image ) && (int) $image > 0 ) {
			return Rsmspark_Content_Widgets_Render::media_url( (int) $image, 'medium' );
		}

		return '';
	}

	/**
	 * @param array<string, mixed> $args Normalized args.
	 * @return array<string, mixed>
	 */
	public static function prepare_template_vars( array $args ) {
		return array(
			'title'         => $args['title'] ?? '',
			'title_color'   => $args['title_color'] ?? '',
			'title_size'    => (int) ( $args['title_size'] ?? 0 ),
			'columns'       => $args['columns'] ?? '4',
			'layout'        => $args['layout'] ?? 'grid',
			'border_enable'           => ! empty( $args['border_enable'] ),
			'border_width'            => (int) ( $args['border_width'] ?? 1 ),
			'border_color'            => $args['border_color'] ?? '#e2e8f0',
			'border_radius'           => $args['border_radius'] ?? 'square',
			'container_border'        => ! empty( $args['container_border'] ),
			'container_border_width'  => (int) ( $args['container_border_width'] ?? 1 ),
			'container_border_color'  => $args['container_border_color'] ?? '#e2e8f0',
			'container_border_radius' => $args['container_border_radius'] ?? 'square',
			'hover_overlay' => false,
			'grayscale'     => false,
			'items'         => $args['items'] ?? array(),
			'style_vars'    => self::section_style_vars( $args ),
		);
	}

	/**
	 * @param array<string, mixed> $args Template variables.
	 * @return string
	 */
	public static function render( array $args ) {
		$vars = isset( $args['style_vars'] ) ? $args : self::prepare_template_vars( $args );
		if ( empty( $vars['items'] ) ) {
			return '';
		}

		return Rsmspark_Content_Widgets_Render::render_template( self::REGISTRY_ID, 'logo-grid.php', $vars );
	}
}
