<?php
/**
 * Buttons widget render layer.
 *
 * Shortcode: [rsmspark_button]
 *
 * @package Rsmspark_Content_Widgets
 */

defined( 'ABSPATH' ) || exit;

/**
 * Rsmspark_Content_Widgets_Widget_Buttons
 */
class Rsmspark_Content_Widgets_Widget_Buttons {

	const REGISTRY_ID = 'buttons';

	/**
	 * @return void
	 */
	public static function register() {
		self::ensure_dependencies();

		Rsmspark_Content_Widgets_Blocks::add(
			'buttons',
			array(
				'api_version'     => 3,
				'title'           => __( 'RSM Button', 'rsm-content-widgets' ),
				'description'     => __( 'Reusable styled button from your library or custom inline settings.', 'rsm-content-widgets' ),
				'category'        => Rsmspark_Content_Widgets_Blocks::BLOCK_CATEGORY,
				'icon'            => 'button',
				'keywords'        => array( 'button', 'cta', 'link', 'rsm' ),
				'supports'        => array( 'html' => false ),
				'attributes'      => self::block_attributes(),
				'render_callback' => array( __CLASS__, 'render_block' ),
			)
		);

		add_action( 'rest_api_init', array( __CLASS__, 'register_rest_routes' ) );
	}

	/**
	 * @return void
	 */
	public static function register_rest_routes() {
		register_rest_route(
			'rsm-content-widgets/v1',
			'/buttons',
			array(
				'methods'             => 'GET',
				'callback'            => array( __CLASS__, 'rest_buttons' ),
				'permission_callback' => static function () {
					return current_user_can( 'edit_posts' );
				},
			)
		);
	}

	/**
	 * @return \WP_REST_Response
	 */
	public static function rest_buttons() {
		if ( ! class_exists( 'Rsmspark_Buttons', false ) ) {
			return rest_ensure_response( array() );
		}

		$posts = get_posts(
			array(
				'post_type'      => Rsmspark_Buttons_CPT::get_post_types(),
				'post_status'    => 'publish',
				'posts_per_page' => 200,
				'orderby'        => 'title',
				'order'          => 'ASC',
			)
		);

		$items = array();
		foreach ( $posts as $post ) {
			if ( ! $post instanceof WP_Post ) {
				continue;
			}
			$items[] = array(
				'id'    => (int) $post->ID,
				'title' => get_the_title( $post ),
			);
		}

		return rest_ensure_response( $items );
	}

	/**
	 * @return void
	 */
	public static function ensure_dependencies() {
		require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/buttons/class-rsmspark-buttons-config.php';
		require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/buttons/class-rsmspark-buttons-cpt.php';
		require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/buttons/class-rsmspark-buttons-render.php';

		if ( ! class_exists( 'Rsmspark_Content_Widgets_Render', false ) ) {
			require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/class-rsmspark-content-widgets-render.php';
		}
	}

	/**
	 * @return array<string, array<string, mixed>>
	 */
	public static function block_attributes() {
		$string = array( 'type' => 'string', 'default' => '' );
		$number = array( 'type' => 'number', 'default' => 0 );
		$bool   = array( 'type' => 'boolean', 'default' => false );

		return array(
			'id'               => $number,
			'source_mode'      => array( 'type' => 'string', 'default' => 'saved' ),
			'text_line_1'      => array( 'type' => 'string', 'default' => __( 'Click Here', 'rsm-content-widgets' ) ),
			'text_line_2'      => $string,
			'icon'             => $string,
			'icon_position'    => array( 'type' => 'string', 'default' => 'left' ),
			'shape'            => array( 'type' => 'string', 'default' => 'rounded' ),
			'border_radius'    => array( 'type' => 'number', 'default' => 8 ),
			'size'             => array( 'type' => 'string', 'default' => 'medium' ),
			'width'            => array( 'type' => 'string', 'default' => 'auto' ),
			'custom_width_px'  => array( 'type' => 'number', 'default' => 200 ),
			'bg_color'         => array( 'type' => 'string', 'default' => '#2563eb' ),
			'bg_hover_color'   => array( 'type' => 'string', 'default' => '#1d4ed8' ),
			'text_color'       => array( 'type' => 'string', 'default' => '#ffffff' ),
			'text_hover_color' => array( 'type' => 'string', 'default' => '#ffffff' ),
			'border_color'     => array( 'type' => 'string', 'default' => 'transparent' ),
			'border_width'     => array( 'type' => 'number', 'default' => 0 ),
			'shadow'           => array( 'type' => 'string', 'default' => 'soft' ),
			'hover_effect'     => array( 'type' => 'string', 'default' => 'lift' ),
			'link_url'         => $string,
			'target_blank'     => $bool,
			'extra_class'      => $string,
		);
	}

	/**
	 * @param array<string, mixed> $atts Shortcode attributes.
	 * @param string               $content Inner content.
	 * @return string
	 */
	public static function shortcode( $atts, $content = '' ) {
		unset( $content );
		return Rsmspark_Buttons::shortcode( 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 );

		$attrs  = self::merge_block_attributes( $attributes, $block );
		$mode   = sanitize_key( (string) ( $attrs['source_mode'] ?? 'saved' ) );
		$id     = absint( $attrs['id'] ?? 0 );
		$force  = class_exists( 'Rsmspark_Content_Widgets_Blocks', false )
			&& Rsmspark_Content_Widgets_Blocks::is_editor_preview_request();

		if ( 'saved' === $mode && $id > 0 ) {
			return self::render_saved_button( $id, $force );
		}

		unset( $attrs['source_mode'], $attrs['id'] );
		$attrs = self::strip_empty_attributes( $attrs );

		return self::render_custom_button( $attrs, $force );
	}

	/**
	 * @param int  $button_id Saved button post ID.
	 * @param bool $force     Skip enabled checks (editor preview).
	 * @return string
	 */
	private static function render_saved_button( $button_id, $force = false ) {
		$button_id = absint( $button_id );
		if ( $button_id <= 0 ) {
			return '';
		}

		if ( $force ) {
			self::ensure_dependencies();
			$config = Rsmspark_Buttons_Config::get( $button_id );
			return Rsmspark_Buttons_Render::render( $config, $button_id, true );
		}

		return Rsmspark_Buttons::shortcode( array( 'id' => $button_id ) );
	}

	/**
	 * @param array<string, mixed> $attrs Inline button attributes.
	 * @param bool                 $force Skip enabled checks (editor preview).
	 * @return string
	 */
	private static function render_custom_button( array $attrs, $force = false ) {
		if ( $force ) {
			self::ensure_dependencies();
			return Rsmspark_Buttons_Render::render( Rsmspark_Buttons_Config::sanitize( $attrs ), 0, true );
		}

		return Rsmspark_Buttons::shortcode( $attrs );
	}

	/**
	 * Merge attributes from WP_Block (parsed block JSON is authoritative).
	 *
	 * @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;
	}

	/**
	 * Drop empty attribute values so block schema defaults do not wipe saved button config.
	 *
	 * @param array<string, mixed> $attributes Attributes.
	 * @return array<string, mixed>
	 */
	private static function strip_empty_attributes( array $attributes ) {
		$clean = array();

		foreach ( $attributes as $key => $value ) {
			if ( is_string( $value ) && '' === trim( $value ) ) {
				continue;
			}
			if ( is_numeric( $value ) && 0 === (int) $value && in_array( $key, array( 'border_radius', 'custom_width_px', 'border_width' ), true ) ) {
				$clean[ $key ] = $value;
				continue;
			}
			if ( is_numeric( $value ) && 0 === (int) $value ) {
				continue;
			}
			if ( false === $value && 'target_blank' !== $key ) {
				continue;
			}
			$clean[ $key ] = $value;
		}

		return $clean;
	}

	/**
	 * Flatten legacy/nested instance keys without removing SiteOrigin metadata.
	 *
	 * @param array<string, mixed> $instance SiteOrigin widget instance.
	 * @return array<string, mixed>
	 */
	public static function normalize_fields( array $instance ) {
		if ( isset( $instance['instance'] ) && is_array( $instance['instance'] ) ) {
			$instance = array_merge( $instance, $instance['instance'] );
		}

		foreach ( $instance as $value ) {
			if ( is_array( $value ) && ( isset( $value['saved_button'] ) || isset( $value['button_id'] ) || isset( $value['text_line_1'] ) ) ) {
				$instance = array_merge( $instance, $value );
			}
		}

		if ( empty( $instance['saved_button'] ) ) {
			foreach ( array( 'button_id', 'rsmspark_button_id', 'selected_button' ) as $legacy_key ) {
				if ( ! empty( $instance[ $legacy_key ] ) ) {
					$instance['saved_button'] = (string) $instance[ $legacy_key ];
					break;
				}
			}
		}

		return $instance;
	}

	/**
	 * @param array<string, mixed> $instance SiteOrigin widget instance.
	 * @return array<string, mixed>
	 */
	public static function normalize_instance( array $instance ) {
		$instance = self::normalize_fields( $instance );
		unset( $instance['panels_info'] );

		return $instance;
	}

	/**
	 * @param array<string, mixed> $instance SiteOrigin widget instance.
	 * @param bool                 $force    Skip enabled checks (builder preview).
	 * @return string
	 */
	public static function render_instance( array $instance, $force = false ) {
		self::ensure_dependencies();

		if (
			! $force
			&& class_exists( 'Rsmspark_Content_Widgets_Settings', false )
			&& ! Rsmspark_Content_Widgets_Settings::is_enabled()
		) {
			return '';
		}

		$atts = self::prepare_from_instance( self::normalize_instance( $instance ) );

		if ( ! empty( $atts['id'] ) ) {
			$button_id = absint( $atts['id'] );
			$config    = Rsmspark_Buttons_Config::get( $button_id );

			if ( '' === trim( (string) $config['text_line_1'] ) ) {
				$post = get_post( $button_id );
				if ( $post && '' !== trim( (string) $post->post_title ) ) {
					$config['text_line_1'] = $post->post_title;
				}
			}

			return Rsmspark_Buttons_Render::render( $config, $button_id, $force );
		}

		return Rsmspark_Buttons_Render::render( Rsmspark_Buttons_Config::sanitize( $atts ), 0, $force );
	}

	/**
	 * @param array<string, mixed> $instance SiteOrigin widget instance.
	 * @return array<string, mixed>
	 */
	public static function prepare_from_instance( array $instance ) {
		$instance = self::normalize_instance( $instance );

		$saved_section  = Rsmspark_Content_Widgets_Render::section_instance( $instance, 'saved' );
		$custom_section = Rsmspark_Content_Widgets_Render::section_instance( $instance, 'custom' );

		if ( is_array( $saved_section ) && $saved_section !== $instance ) {
			$instance = array_merge( $instance, $saved_section );
		}

		if ( is_array( $custom_section ) && $custom_section !== $instance ) {
			$instance = array_merge( $instance, $custom_section );
		}

		$button_id = absint(
			$instance['saved_button']
			?? $instance['button_id']
			?? $instance['rsmspark_button_id']
			?? $instance['selected_button']
			?? $instance['id']
			?? 0
		);
		$mode      = sanitize_key( (string) ( $instance['source_mode'] ?? '' ) );
		$link_url  = '';

		if ( isset( $instance['link_url'] ) && is_array( $instance['link_url'] ) ) {
			$link_url = Rsmspark_Content_Widgets_Render::link_url( $instance['link_url'] );
		} elseif ( isset( $instance['link_url'] ) ) {
			$link_url = Rsmspark_Buttons_Config::sanitize_link_url( $instance['link_url'] );
		}

		if ( '' === $mode ) {
			$mode = $button_id > 0 ? 'saved' : 'custom';
		}

		if ( 'saved' === $mode && $button_id > 0 ) {
			$saved = array( 'id' => $button_id );
			if ( '' !== $link_url ) {
				$saved['link_url']  = $link_url;
				$saved['link_type'] = 'url';
			}

			return $saved;
		}

		$custom = array();
		foreach ( array_keys( Rsmspark_Buttons_Config::defaults() ) as $key ) {
			if ( isset( $instance[ $key ] ) && '' !== (string) $instance[ $key ] ) {
				$custom[ $key ] = $instance[ $key ];
			}
		}

		if ( is_array( $custom_section ) && $custom_section !== $instance ) {
			foreach ( $custom_section as $key => $value ) {
				if ( '' !== (string) $value ) {
					$custom[ $key ] = $value;
				}
			}
		}

		if ( isset( $custom['link_url'] ) && is_array( $custom['link_url'] ) ) {
			$custom['link_url']  = Rsmspark_Content_Widgets_Render::link_url( $custom['link_url'] );
			$custom['link_type'] = 'url';
		} elseif ( isset( $instance['link_url'] ) && is_array( $instance['link_url'] ) ) {
			$custom['link_url']  = Rsmspark_Content_Widgets_Render::link_url( $instance['link_url'] );
			$custom['link_type'] = 'url';
		} elseif ( '' !== $link_url ) {
			$custom['link_url']  = $link_url;
			$custom['link_type'] = 'url';
		}

		return $custom;
	}

	/**
	 * @param array<string, mixed> $instance SiteOrigin widget instance.
	 * @return array<string, mixed>
	 */
	public static function prepare_from_siteorigin_instance( array $instance ) {
		return self::prepare_from_instance( self::normalize_instance( $instance ) );
	}

	/**
	 * @param array<string, mixed> $attrs Block attributes.
	 * @return array<string, mixed>
	 */
	public static function instance_from_atts( array $attrs ) {
		$id   = absint( $attrs['id'] ?? 0 );
		$mode = sanitize_key( (string) ( $attrs['source_mode'] ?? '' ) );

		if ( ( 'saved' === $mode || ( '' === $mode && $id > 0 ) ) && $id > 0 ) {
			return array(
				'source_mode'  => 'saved',
				'saved_button' => (string) $id,
			);
		}

		$out = array( 'source_mode' => 'custom' );
		foreach ( self::block_attributes() as $key => $definition ) {
			if ( in_array( $key, array( 'id', 'source_mode' ), true ) ) {
				continue;
			}
			if ( array_key_exists( $key, $attrs ) ) {
				$out[ $key ] = $attrs[ $key ];
			} elseif ( array_key_exists( 'default', $definition ) ) {
				$out[ $key ] = $definition['default'];
			}
		}

		return $out;
	}

	/**
	 * @param array<string, mixed> $instance SiteOrigin or import instance.
	 * @return array<string, mixed>
	 */
	public static function sanitize_instance( array $instance ) {
		unset( $instance['import_export'], $instance['panels_info'] );

		return self::prepare_from_siteorigin_instance( $instance );
	}

}
