<?php
/**
 * Giveaway Preview REST API Controller
 *
 * Handles REST API endpoints for previewing giveaways.
 *
 * @package SimpleGiveaways
 * @since 2.49.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class GiveASAP_Preview_REST_Controller
 */
class GiveASAP_Preview_REST_Controller {

	/**
	 * Namespace for the REST API.
	 *
	 * @var string
	 */
	const NAMESPACE = 'giveasap/v1';

	/**
	 * Constructor.
	 */
	public function __construct() {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
		add_action( 'admin_init', array( $this, 'handle_iframe_preview' ) );
	}

	/**
	 * Register REST API routes.
	 */
	public function register_routes() {
		register_rest_route(
			self::NAMESPACE,
			'/preview/(?P<id>\d+)',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_preview' ),
				'permission_callback' => array( $this, 'check_permissions' ),
				'args'                => array(
					'id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
				),
			)
		);
	}

	/**
	 * Check if the user has permission to view the preview.
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return bool|WP_Error
	 */
	public function check_permissions( $request ) {
		if ( ! current_user_can( 'edit_posts' ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'You do not have permission to preview giveaways.', 'giveasap' ),
				array( 'status' => 403 )
			);
		}

		return true;
	}

	/**
	 * Handle iframe preview via admin_init hook.
	 * This outputs HTML directly instead of JSON.
	 */
	public function handle_iframe_preview() {
		// Check if this is our iframe preview request. The builder POSTs the
		// settings (they exceed URL length limits as GET parameters), so read
		// from $_REQUEST to support both transports.
		if ( ! isset( $_REQUEST['giveasap_iframe_preview'] ) || ! isset( $_REQUEST['giveaway_id'] ) ) {
			return;
		}

		// Verify permissions
		if ( ! current_user_can( 'edit_posts' ) ) {
			wp_die( __( 'You do not have permission to preview giveaways.', 'giveasap' ) );
		}

		$nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'giveasap_builder_save' ) ) {
			wp_die( __( 'Your session expired. Please reload the giveaway and try again.', 'giveasap' ) );
		}

		$giveaway_id = absint( $_REQUEST['giveaway_id'] );
		$post        = get_post( $giveaway_id );

		if ( ! $post || 'giveasap' !== $post->post_type ) {
			wp_die( __( 'Giveaway not found.', 'giveasap' ) );
		}

		// An auto-draft has no saved settings meta and cannot be rendered.
		if ( 'auto-draft' === $post->post_status ) {
			wp_die( __( 'Save as draft to use the visual builder.', 'giveasap' ) );
		}

		// Get preview settings from request
		$preview_settings = $this->get_preview_settings_from_request_array( $_REQUEST );

		// Read the preview step
		$preview_step = isset( $_REQUEST['preview_step'] ) ? absint( $_REQUEST['preview_step'] ) : 1;

		// Temporarily apply preview settings using filters
		$this->apply_preview_settings( $giveaway_id, $preview_settings );

		// Output HTML with proper headers
		$this->output_iframe_html( $giveaway_id, $preview_step );
		exit;
	}

	/**
	 * Get preview settings from request array (GET parameters).
	 *
	 * @param array $request
	 * @return array
	 */
	private function get_preview_settings_from_request_array( $request ) {
		$settings = array();

		// Display settings
		$settings['background_color'] = isset( $request['background_color'] ) ? sanitize_hex_color( $request['background_color'] ) : '';
		$settings['background_image'] = isset( $request['background_image'] ) ? absint( $request['background_image'] ) : 0;
		$settings['logo'] = isset( $request['logo'] ) ? absint( $request['logo'] ) : 0;
		$settings['logo_link'] = isset( $request['logo_link'] ) ? esc_url_raw( $request['logo_link'] ) : '';
		$page_layout = isset( $request['page_layout'] ) ? sanitize_text_field( $request['page_layout'] ) : '';
		$settings['page_layout'] = ( 'show_header' === $page_layout || '1' === (string) $page_layout ) ? '1' : '0';

		// Prize settings
		$settings['prize_name'] = isset( $request['prize_name'] ) ? sanitize_text_field( $request['prize_name'] ) : '';
		$settings['prize_value'] = isset( $request['prize_value'] ) ? sanitize_text_field( $request['prize_value'] ) : '';
		$settings['winners'] = isset( $request['winners'] ) ? absint( $request['winners'] ) : 0;
		$settings['prizes_layout'] = isset( $request['prizes_layout'] ) ? sanitize_text_field( $request['prizes_layout'] ) : '';

		// General settings
		$settings['type'] = isset( $request['type'] ) ? sanitize_text_field( $request['type'] ) : '';
		$settings['giveaway_page'] = isset( $request['giveaway_page'] ) ? esc_url_raw( $request['giveaway_page'] ) : '';

		// Prizes repeater
		if ( ! empty( $request['giveasap_prizes_json'] ) ) {
			$decoded = json_decode( wp_unslash( $request['giveasap_prizes_json'] ), true );
			$settings['prizes_rows'] = is_array( $decoded ) ? $decoded : array();
		}

		// Extra entries actions repeater. An empty array is meaningful here
		// (all actions removed in the builder), so only skip when absent.
		if ( ! empty( $request['giveasap_actions_json'] ) ) {
			$decoded = json_decode( wp_unslash( $request['giveasap_actions_json'] ), true );
			if ( is_array( $decoded ) ) {
				$settings['actions_rows'] = $decoded;
			}
		}

		return $settings;
	}

	/**
	 * Get the giveaway preview HTML.
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return WP_REST_Response
	 */
	public function get_preview( $request ) {
		$giveaway_id = $request->get_param( 'id' );
		$post        = get_post( $giveaway_id );

		if ( ! $post || 'giveasap' !== $post->post_type ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'error'   => __( 'Giveaway not found.', 'giveasap' ),
				),
				404
			);
		}

		// Generate the preview HTML using the shortcode function
		$preview_html = $this->render_giveaway_preview( $giveaway_id );

		return new WP_REST_Response(
			array(
				'success' => true,
				'html'    => $preview_html,
				'id'      => $giveaway_id,
			),
			200
		);
	}

	/**
	 * Render the giveaway preview HTML.
	 *
	 * @param int $giveaway_id The giveaway ID.
	 * @return string
	 */
	private function render_giveaway_preview( $giveaway_id ) {
		ob_start();

		// Use the shortcode to render the giveaway
		$shortcode_atts = array(
			'id'                  => $giveaway_id,
			'title'               => '1',
			'prizes'              => '1',
			'show_form'           => '1',
			'show_total_entries'  => '0',
			'show_entries'        => '0',
			'countdown_in_header' => '0',
			'hide_winners_number' => '0',
			'hide_prize_value'    => '0',
			'hide_prize_title'    => '0',
			'content'             => '1',
			'rules'               => '1',
		);

		// Call the shortcode function
		if ( function_exists( 'giveasap_shortcode' ) ) {
			echo giveasap_shortcode( $shortcode_atts );
		}

		return ob_get_clean();
	}

	/**
	 * Get the iframe preview HTML with full page wrapper.
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return void
	 */
	public function get_iframe_preview( $request ) {
		$giveaway_id = $request->get_param( 'giveaway_id' );
		$post        = get_post( $giveaway_id );

		if ( ! $post || 'giveasap' !== $post->post_type ) {
			wp_die( __( 'Giveaway not found.', 'giveasap' ) );
		}

		// Get preview settings from request
		$preview_settings = $this->get_preview_settings_from_request( $request );

		// Temporarily apply preview settings using filters
		$this->apply_preview_settings( $giveaway_id, $preview_settings );

		// Output the full HTML page
		$this->render_iframe_html( $giveaway_id );
		exit;
	}

	/**
	 * Get preview settings from the REST request.
	 *
	 * @param WP_REST_Request $request
	 * @return array
	 */
	private function get_preview_settings_from_request( $request ) {
		$settings = array();

		// Display settings
		$settings['background_color'] = sanitize_hex_color( $request->get_param( 'background_color' ) );
		$settings['background_image'] = absint( $request->get_param( 'background_image' ) );
		$settings['logo'] = absint( $request->get_param( 'logo' ) );
		$settings['logo_link'] = esc_url_raw( $request->get_param( 'logo_link' ) );
		$page_layout = sanitize_text_field( $request->get_param( 'page_layout' ) );
		$settings['page_layout'] = ( 'show_header' === $page_layout || '1' === (string) $page_layout ) ? '1' : '0';

		// Prize settings
		$settings['prize_name'] = sanitize_text_field( $request->get_param( 'prize_name' ) );
		$settings['prize_value'] = sanitize_text_field( $request->get_param( 'prize_value' ) );
		$settings['winners'] = absint( $request->get_param( 'winners' ) );
		$settings['prizes_layout'] = sanitize_text_field( $request->get_param( 'prizes_layout' ) );

		// General settings
		$settings['type'] = sanitize_text_field( $request->get_param( 'type' ) );
		$settings['giveaway_page'] = esc_url_raw( $request->get_param( 'giveaway_page' ) );

		return $settings;
	}

	/**
	 * Apply preview settings via filters.
	 *
	 * @param int   $giveaway_id
	 * @param array $settings
	 */
	private function apply_preview_settings( $giveaway_id, $settings ) {
		global $wpdb;
		
		// Get existing meta values directly from DB to avoid recursive filter calls
		$display_meta = $wpdb->get_var( $wpdb->prepare(
			"SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = 'giveasap_display' LIMIT 1",
			$giveaway_id
		) );
		$prize_meta = $wpdb->get_var( $wpdb->prepare(
			"SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = 'giveasap_prize' LIMIT 1",
			$giveaway_id
		) );
		$extra_entries_meta = $wpdb->get_var( $wpdb->prepare(
			"SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = 'giveasap_extra_entries' LIMIT 1",
			$giveaway_id
		) );

        add_filter( 'sg_giveaway_get_subscriber', function( $bool ){
            if ( $bool ) {
                return $bool;
            }

            return [
                'id' => 0,
                'entries' => 100,
                'email' => 'example@example.com',
                'ref_id' => 'preview'
            ];
        });

		// Add filters to override meta values with preview settings
		add_filter( 'get_post_metadata', function( $value, $object_id, $meta_key, $single ) use ( $giveaway_id, $settings, $display_meta, $prize_meta, $extra_entries_meta ) {
			if ( $object_id !== $giveaway_id ) {
				return $value;
			}

			// Handle extra entries actions
			if ( 'giveasap_extra_entries' === $meta_key && isset( $settings['actions_rows'] ) ) {
				$existing = maybe_unserialize( $extra_entries_meta );
				if ( ! is_array( $existing ) ) {
					$existing = array();
				}

				$sanitized = array();
				foreach ( $settings['actions_rows'] as $row ) {
					if ( ! is_array( $row ) ) {
						continue;
					}
					$clean = array();
					foreach ( $row as $key => $val ) {
						$key = sanitize_key( $key );
						if ( is_array( $val ) ) {
							$clean[ $key ] = array_map( 'sanitize_text_field', $val );
						} else {
							// Textarea fields carry newlines that matter for display.
							$clean[ $key ] = sanitize_textarea_field( $val );
						}
					}
					$sanitized[] = $clean;
				}

				$existing['entries_actions'] = $sanitized;

				return array( $existing );
			}

			$meta_map = array(
				'giveasap_type'              => 'type',
				'sg_giveaway_page'           => 'giveaway_page',
				'giveasap_prize'             => null, // Complex mapping
				'giveasap_display'           => null, // Complex mapping
			);

			// Handle display settings
			if ( 'giveasap_display' === $meta_key ) {
				$existing = maybe_unserialize( $display_meta );
				if ( ! is_array( $existing ) ) {
					$existing = array();
				}

				if ( ! empty( $settings['background_color'] ) ) {
					$existing['background_color'] = $settings['background_color'];
				}
				if ( ! empty( $settings['background_image'] ) ) {
					$existing['background_image'] = $settings['background_image'];
				}
				if ( ! empty( $settings['logo'] ) ) {
					$existing['logo'] = $settings['logo'];
				}
				if ( ! empty( $settings['logo_link'] ) ) {
					$existing['logo_link'] = $settings['logo_link'];
				}
				if ( isset( $settings['page_layout'] ) ) {
					$existing['page_layout'] = $settings['page_layout'];
				}

				return array( $existing );
			}

			// Handle prize settings
			if ( 'giveasap_prize' === $meta_key ) {
				$existing = maybe_unserialize( $prize_meta );
				if ( ! is_array( $existing ) ) {
					$existing = array();
				}

				if ( ! empty( $settings['prize_name'] ) ) {
					$existing['prize'] = $settings['prize_name'];
				}
				if ( ! empty( $settings['prize_value'] ) ) {
					$existing['value'] = $settings['prize_value'];
				}
				if ( ! empty( $settings['winners'] ) ) {
					$existing['winners'] = $settings['winners'];
				}
				if ( ! empty( $settings['prizes_layout'] ) ) {
					$existing['layout'] = $settings['prizes_layout'];
				}
				if ( isset( $settings['prizes_rows'] ) && is_array( $settings['prizes_rows'] ) ) {
					$sanitized = array();
					foreach ( $settings['prizes_rows'] as $row ) {
						if ( ! is_array( $row ) ) {
							continue;
						}
						$clean = array();
						foreach ( $row as $key => $val ) {
							$clean[ sanitize_key( $key ) ] = sanitize_text_field( $val );
						}
						$sanitized[] = $clean;
					}
					$existing['prizes'] = $sanitized;
				}

				return array( $existing );
			}

			// Handle simple direct mappings
			if ( isset( $meta_map[ $meta_key ] ) && null !== $meta_map[ $meta_key ] ) {
				$setting_key = $meta_map[ $meta_key ];
				if ( ! empty( $settings[ $setting_key ] ) ) {
					return array( $settings[ $setting_key ] );
				}
			}

			return $value;
		}, 10, 4 );
	}

	/**
	 * Output the full HTML page for the iframe with proper headers.
	 *
	 * @param int $giveaway_id
	 */
	private function output_iframe_html( $giveaway_id, $preview_step = 1 ) {
		global $wp_scripts, $wp_styles;

		// Send HTML headers
		if ( ! headers_sent() ) {
			header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
			header( 'X-Frame-Options: SAMEORIGIN' );
		}

		// Force load giveaway styles and scripts
		$version = gasap()->version();
		
		// Enqueue shortcode CSS
		wp_enqueue_style( 'sg-shortcode', GASAP_URI . 'assets/dist/css/shortcode.css', array(), $version );
		
		// Enqueue scripts via main plugin class
		gasap()->enqueue_scripts();

		?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title><?php echo esc_html( get_the_title( $giveaway_id ) ); ?> - <?php _e( 'Preview', 'giveasap' ); ?></title>
	<?php
	// Print all styles
	wp_print_styles();
	?>
	<style>
		body {
			margin: 0;
			padding: 20px;
			background: #f0f0f1;
			font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
		}
		.giveasap-preview-container {
			max-width: 1200px;
			margin: 0 auto;
			background: #fff;
			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
		}
	</style>
</head>
<body>
	<div class="giveasap-preview-container">
		<?php
		if ( 2 === $preview_step ) {
			// Override step via the filter (for get_step() calls in templates)
			add_filter( 'sg_front_get_step', function( $step, $front ) {
				return 2;
			}, 10, 2 );

			// Skip captcha processing in preview
			add_filter( 'sg_process_captcha', '__return_false' );
		}

		// Render the giveaway shortcode
		if ( function_exists( 'giveasap_shortcode' ) ) {
			echo giveasap_shortcode( array(
				'id'                  => $giveaway_id,
				'title'               => '1',
				'prizes'              => '1',
				'show_form'           => '1',
				'show_total_entries'  => '0',
				'show_entries'        => '0',
				'countdown_in_header' => '0',
				'hide_winners_number' => '0',
				'hide_prize_value'    => '0',
				'hide_prize_title'    => '0',
				'content'             => '1',
				'rules'               => '1',
			) );
		}
		?>
	</div>
	<?php
	// Print all scripts
	wp_print_scripts();
	?>
</body>
</html>
		<?php
	}
}

// Initialize the REST controller
new GiveASAP_Preview_REST_Controller();
