<?php
/**
 * Unified widget JSON import/export AJAX (SiteOrigin admin + block editor parse).
 *
 * @package Rsmspark_Content_Widgets
 */

defined( 'ABSPATH' ) || exit;

require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/class-rsmspark-content-widgets-widget-json-registry.php';
require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/class-rsmspark-content-widgets-widget-json-config.php';

/**
 * Rsmspark_Content_Widgets_Widget_Json
 */
class Rsmspark_Content_Widgets_Widget_Json {

	/**
	 * @return void
	 */
	public static function init() {
		add_action( 'wp_ajax_rsmspark_cw_widget_json', array( __CLASS__, 'handle' ) );
	}

	/**
	 * @return void
	 */
	public static function handle() {
		if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_theme_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission denied.', 'rsm-content-widgets' ) ), 403 );
		}

		check_ajax_referer( 'rsmspark_cw_widget_json', 'nonce' );

		$widget = sanitize_key( (string) ( $_POST['widget'] ?? '' ) );
		$mode   = sanitize_key( (string) ( $_POST['mode'] ?? '' ) );

		if ( ! Rsmspark_Content_Widgets_Widget_Json_Registry::supports_widget_json( $widget ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'This widget does not support JSON import/export.', 'rsm-content-widgets' ),
				),
				400
			);
		}

		if ( 'export' === $mode ) {
			self::ajax_export( $widget );
		}

		if ( 'import' === $mode ) {
			self::ajax_import( $widget );
		}

		if ( 'parse' === $mode ) {
			self::ajax_parse( $widget );
		}

		wp_send_json_error( array( 'message' => __( 'Invalid request.', 'rsm-content-widgets' ) ), 400 );
	}

	/**
	 * @param string $widget Widget registry id.
	 * @return void
	 */
	private static function ajax_export( $widget ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified in ::handle() via check_ajax_referer().
		$raw      = Rsmspark_Content_Widgets_Widget_Json_Config::read_post_string( 'instance' );
		$instance = json_decode( $raw, true );
		$instance = is_array( $instance ) ? $instance : array();
		$label    = isset( $_POST['label'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['label'] ) ) : '';
		// phpcs:enable WordPress.Security.NonceVerification.Missing

		wp_send_json_success( self::build_export_payload( $widget, $instance, $label ) );
	}

	/**
	 * @param string $widget Widget registry id.
	 * @return void
	 */
	private static function ajax_import( $widget ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified in ::handle() via check_ajax_referer().
		$raw     = Rsmspark_Content_Widgets_Widget_Json_Config::read_post_string( 'payload' );
		$current = Rsmspark_Content_Widgets_Widget_Json_Config::read_post_string( 'instance' );
		// phpcs:enable WordPress.Security.NonceVerification.Missing
		$parsed  = self::parse_import_payload( $widget, $raw );

		if ( null === $parsed ) {
			wp_send_json_error(
				array(
					'message' => self::import_error_message( $widget ),
				),
				400
			);
		}

		$instance = json_decode( $current, true );
		$instance = is_array( $instance ) ? $instance : array();

		wp_send_json_success(
			array(
				'config'     => $parsed['config'],
				'label'      => $parsed['label'],
				'attributes' => $parsed['attributes'],
				'instance'   => self::merge_siteorigin_instance( $widget, $instance, $parsed['config'] ),
			)
		);
	}

	/**
	 * @param string $widget Widget registry id.
	 * @return void
	 */
	private static function ajax_parse( $widget ) {
		// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified in ::handle() via check_ajax_referer().
		$raw = Rsmspark_Content_Widgets_Widget_Json_Config::read_post_string( 'payload' );
		// phpcs:enable WordPress.Security.NonceVerification.Missing
		$parsed = self::parse_import_payload( $widget, $raw );

		if ( null === $parsed ) {
			wp_send_json_error(
				array(
					'message' => self::import_error_message( $widget ),
				),
				400
			);
		}

		wp_send_json_success( $parsed );
	}

	/**
	 * @param string               $widget   Widget registry id.
	 * @param array<string, mixed> $instance SiteOrigin instance.
	 * @param string               $label    Export label.
	 * @return array<string, mixed>
	 */
	public static function build_export_payload( $widget, array $instance, $label = '' ) {
		$dedicated = Rsmspark_Content_Widgets_Widget_Json_Registry::dedicated_handler_class( $widget );

		if ( $dedicated && method_exists( $dedicated, 'build_export_payload' ) ) {
			$payload = $dedicated::build_export_payload( $instance, $label );
			if ( ! isset( $payload['widget'] ) ) {
				$payload['widget'] = sanitize_key( (string) $widget );
			}
			if ( ! isset( $payload['attributes'] ) && method_exists( $dedicated, 'to_block_attributes' ) ) {
				$payload['attributes'] = $dedicated::to_block_attributes(
					method_exists( $dedicated, 'from_siteorigin_instance' )
						? $dedicated::from_siteorigin_instance( $instance )
						: $instance
				);
			}
			return $payload;
		}

		return Rsmspark_Content_Widgets_Widget_Json_Config::build_export_payload( $widget, $instance, $label );
	}

	/**
	 * @param string $widget  Widget registry id.
	 * @param mixed  $payload Raw JSON or array.
	 * @return array{config: array<string, mixed>, label: string, attributes: array<string, mixed>}|null
	 */
	public static function parse_import_payload( $widget, $payload ) {
		$dedicated = Rsmspark_Content_Widgets_Widget_Json_Registry::dedicated_handler_class( $widget );

		if ( $dedicated && method_exists( $dedicated, 'parse_import_payload' ) ) {
			$parsed = $dedicated::parse_import_payload( $payload );
			if ( null === $parsed ) {
				return null;
			}

			$attributes = $parsed['attributes'] ?? array();
			if ( empty( $attributes ) && method_exists( $dedicated, 'to_block_attributes' ) ) {
				$attributes = $dedicated::to_block_attributes( $parsed['config'] );
			}

			return array(
				'label'      => (string) ( $parsed['label'] ?? '' ),
				'config'     => is_array( $parsed['config'] ?? null ) ? $parsed['config'] : array(),
				'attributes' => is_array( $attributes ) ? $attributes : array(),
			);
		}

		return Rsmspark_Content_Widgets_Widget_Json_Config::parse_import_payload( $widget, $payload );
	}

	/**
	 * @param string               $widget   Widget registry id.
	 * @param array<string, mixed> $instance Current SO instance.
	 * @param array<string, mixed> $config   Import config.
	 * @return array<string, mixed>
	 */
	public static function merge_siteorigin_instance( $widget, array $instance, array $config ) {
		$dedicated = Rsmspark_Content_Widgets_Widget_Json_Registry::dedicated_handler_class( $widget );

		if ( $dedicated && method_exists( $dedicated, 'merge_siteorigin_instance' ) ) {
			return $dedicated::merge_siteorigin_instance( $instance, $config );
		}

		return Rsmspark_Content_Widgets_Widget_Json_Config::merge_siteorigin_instance( $widget, $instance, $config );
	}

	/**
	 * @param string $widget Widget registry id.
	 * @return string
	 */
	private static function import_error_message( $widget ) {
		$defs  = Rsmspark_Content_Widgets_Registry::definitions();
		$label = isset( $defs[ $widget ]['label'] ) ? (string) $defs[ $widget ]['label'] : $widget;

		return sprintf(
			/* translators: %s: widget label */
			__( 'Paste valid RSM %s JSON export data (widget or block export).', 'rsm-content-widgets' ),
			$label
		);
	}
}
