<?php
/**
 * WordPress widget: render a Divi Library layout in widget areas (Divi 5 pipeline).
 *
 * Widget id base `dsm_widget_library` matches legacy `widget_dsm_widget_library` option entries.
 *
 * @package DiviSupreme
 */

declare(strict_types=1);

namespace DiviSupreme\Includes;

if ( ! defined( 'ABSPATH' ) ) {
	die( 'Direct access forbidden.' );
}

/**
 * Renders library content via {@see DiviLibraryLayoutRenderer::render_layout()}.
 */
class Dsm_Widget_Library extends \WP_Widget {

	/**
	 * Canonical instance key for the selected layout post ID.
	 *
	 * @var string
	 */
	private const INSTANCE_KEY_LAYOUT = 'layout';

	/**
	 * Constructor.
	 */
	public function __construct() {
		parent::__construct(
			'dsm_widget_library',
			esc_html__( 'Divi Supreme Library', 'dsm-supreme-modules-pro-for-divi' ),
			array(
				'classname'   => 'dsm_widget_library',
				'description' => esc_html__( 'Display a layout from the Divi Library.', 'dsm-supreme-modules-pro-for-divi' ),
			),
			array(
				'width'  => 400,
				'height' => 200,
			)
		);
	}

	/**
	 * Front-end output.
	 *
	 * @param array<string, mixed> $args     Widget args.
	 * @param array<string, mixed> $instance Saved widget settings.
	 * @return void
	 */
	public function widget( $args, $instance ) {
		$instance = is_array( $instance ) ? $instance : array();

		$layout_id = self::resolve_layout_post_id_from_instance( $instance );

		if ( $layout_id <= 0 ) {
			return;
		}

		$html = DiviLibraryLayoutRenderer::render_layout( $layout_id, 'dsm_widget_library' );

		if ( '' === trim( (string) $html ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Theme-supplied widget wrappers.
		echo $args['before_widget'];

		$title = isset( $instance['title'] ) ? (string) $instance['title'] : '';

		if ( '' !== trim( $title ) ) {
			/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
			$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Theme-supplied title wrappers.
			echo $args['before_title'] . $title . $args['after_title'];
		}

		echo '<div class="dsm-widget-library-layout">';
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Divi Builder layout HTML.
		echo $html;
		echo '</div>';

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Theme-supplied widget wrappers.
		echo $args['after_widget'];
	}

	/**
	 * Admin form.
	 *
	 * @param array<string, mixed> $instance Current settings.
	 * @return void
	 */
	public function form( $instance ) {
		$instance = is_array( $instance ) ? $instance : array();

		$title        = isset( $instance['title'] ) ? (string) $instance['title'] : '';
		$selected_raw = self::get_layout_value_from_instance( $instance );
		$selected     = ( 'none' === $selected_raw || '' === $selected_raw ) ? 'none' : (string) absint( $selected_raw );

		$field_id   = $this->get_field_id( 'title' );
		$field_name = $this->get_field_name( 'title' );

		$layout_field_id   = $this->get_field_id( self::INSTANCE_KEY_LAYOUT );
		$layout_field_name = $this->get_field_name( self::INSTANCE_KEY_LAYOUT );

		$options = DsmLibraryLayoutSelectOptions::get_options();
		?>
		<p>
			<label for="<?php echo esc_attr( $field_id ); ?>">
				<?php esc_html_e( 'Title:', 'dsm-supreme-modules-pro-for-divi' ); ?>
			</label>
			<input class="widefat" id="<?php echo esc_attr( $field_id ); ?>" name="<?php echo esc_attr( $field_name ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
		</p>
		<p>
			<label for="<?php echo esc_attr( $layout_field_id ); ?>">
				<?php esc_html_e( 'Divi Library layout:', 'dsm-supreme-modules-pro-for-divi' ); ?>
			</label>
			<select class="widefat" id="<?php echo esc_attr( $layout_field_id ); ?>" name="<?php echo esc_attr( $layout_field_name ); ?>">
				<?php foreach ( $options as $value => $label ) : ?>
					<?php
					$opt_value = (string) $value;
					if ( 'none' === $opt_value ) {
						$compare = 'none';
					} else {
						$compare = (string) absint( $opt_value );
					}
					?>
					<option value="<?php echo esc_attr( $opt_value ); ?>" <?php selected( $compare, $selected ); ?>>
						<?php echo esc_html( (string) $label ); ?>
					</option>
				<?php endforeach; ?>
			</select>
		</p>
		<?php
	}

	/**
	 * Save widget settings.
	 *
	 * @param array<string, mixed> $new_instance New values.
	 * @param array<string, mixed> $old_instance Previous values.
	 * @return array<string, mixed>
	 */
	public function update( $new_instance, $old_instance ) {
		$old_instance = is_array( $old_instance ) ? $old_instance : array();
		$new_instance = is_array( $new_instance ) ? $new_instance : array();

		$instance = $old_instance;

		if ( isset( $new_instance['title'] ) ) {
			$instance['title'] = sanitize_text_field( (string) $new_instance['title'] );
		} else {
			$instance['title'] = '';
		}

		$layout_raw = isset( $new_instance[ self::INSTANCE_KEY_LAYOUT ] ) ? $new_instance[ self::INSTANCE_KEY_LAYOUT ] : '';

		if ( 'none' === $layout_raw || '' === (string) $layout_raw ) {
			$instance[ self::INSTANCE_KEY_LAYOUT ] = '';
		} else {
			$instance[ self::INSTANCE_KEY_LAYOUT ] = (string) absint( $layout_raw );
		}

		return $instance;
	}

	/**
	 * Raw layout selection from instance (supports legacy keys).
	 *
	 * @param array<string, mixed> $instance Widget instance.
	 * @return string
	 */
	private static function get_layout_value_from_instance( array $instance ): string {
		if ( isset( $instance[ self::INSTANCE_KEY_LAYOUT ] ) && '' !== (string) $instance[ self::INSTANCE_KEY_LAYOUT ] ) {
			return (string) $instance[ self::INSTANCE_KEY_LAYOUT ];
		}

		$legacy_keys = array( 'library', 'library_id', 'divi_library', 'dsm_layout', 'layout_id' );

		foreach ( $legacy_keys as $key ) {
			if ( isset( $instance[ $key ] ) && '' !== (string) $instance[ $key ] && 'none' !== (string) $instance[ $key ] ) {
				return (string) $instance[ $key ];
			}
		}

		return '';
	}

	/**
	 * Normalized layout post ID for rendering.
	 *
	 * @param array<string, mixed> $instance Widget instance.
	 * @return int
	 */
	private static function resolve_layout_post_id_from_instance( array $instance ): int {
		$raw = self::get_layout_value_from_instance( $instance );

		if ( 'none' === $raw || '' === $raw ) {
			return 0;
		}

		return DiviLibraryLayoutRenderer::normalize_post_id( $raw );
	}
}
