<?php
/**
 * AJAX preview controller for Mail Doctor emails.
 *
 * @package MailDoctor
 */

namespace MailDoctor\Email\Modules;

use MailDoctor\Email\CacheService;
use MailDoctor\Email\PreviewDataFactory;

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

/**
 * Handles live preview rendering for the dual-mode editor.
 */
class PreviewController {


	/**
	 * Register the AJAX action hook.
	 *
	 * @return void
	 */
	public static function register(): void {
		add_action( 'wp_ajax_mail_doctor_live_preview', array( __CLASS__, 'handle' ) );
	}

	/**
	 * Process the live preview request.
	 *
	 * @return void
	 */
	public static function handle(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) && ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'You do not have permission to preview templates.', 'mail-doctor' ),
				),
				403
			);
		}

		check_ajax_referer( 'mail_doctor_live_preview', 'nonce' );

		$email_id = isset( $_POST['emailId'] ) ? sanitize_key( wp_unslash( $_POST['emailId'] ) ) : '';
		$locale   = isset( $_POST['locale'] ) ? sanitize_text_field( wp_unslash( $_POST['locale'] ) ) : '';
		$mode     = isset( $_POST['mode'] ) ? sanitize_key( wp_unslash( $_POST['mode'] ) ) : 'html';
		$status   = isset( $_POST['status'] ) ? sanitize_key( wp_unslash( $_POST['status'] ) ) : 'processing';

		if ( '' === $locale ) {
			$locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
		}

		$template_id = isset( $_POST['templateId'] ) ? sanitize_text_field( wp_unslash( $_POST['templateId'] ) ) : '';
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized individually below.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized individually below.
		$template_input = isset( $_POST['template'] ) && is_array( $_POST['template'] ) ? wp_unslash( $_POST['template'] ) : array();

		$payload = array(
			'emailId'    => $email_id,
			'locale'     => $locale,
			'status'     => $status,
			'orderId'    => isset( $_POST['orderId'] ) ? absint( wp_unslash( $_POST['orderId'] ) ) : 0,
			'mode'       => $mode,
			'templateId' => $template_id,
			'template'   => array(
				'id'      => $template_id,
				'subject' => isset( $template_input['subject'] ) ? wp_kses_post( $template_input['subject'] ) : '',
				'heading' => isset( $template_input['heading'] ) ? wp_kses_post( $template_input['heading'] ) : '',
				'html'    => isset( $template_input['html'] ) ? wp_kses_post( $template_input['html'] ) : '',
				'css'     => isset( $template_input['css'] ) ? wp_kses_post( $template_input['css'] ) : '',
			),
		);

		try {
			$response = self::preview( $payload );
			wp_send_json_success( $response );
		} catch ( \InvalidArgumentException $exception ) {
			wp_send_json_error(
				array(
					'message' => $exception->getMessage(),
				),
				400
			);
		} catch ( \RuntimeException $exception ) {
			wp_send_json_error(
				array(
					'message' => $exception->getMessage(),
				),
				500
			);
		}
	}

	/**
	 * Build preview payload using sanitized data.
	 *
	 * @param array<string,mixed> $args Preview arguments.
	 * @return array<string,mixed>
	 */
	public static function preview( array $args ): array {
		$email_id = isset( $args['emailId'] ) ? sanitize_key( (string) $args['emailId'] ) : '';
		$mode     = isset( $args['mode'] ) ? sanitize_key( (string) $args['mode'] ) : 'html';
		$locale   = isset( $args['locale'] ) ? sanitize_text_field( (string) $args['locale'] ) : ( function_exists( 'determine_locale' ) ? determine_locale() : get_locale() );

		if ( '' === $email_id ) {
			throw new \InvalidArgumentException( esc_html__( 'An email type is required for preview.', 'mail-doctor' ) );
		}

		$template_input = isset( $args['template'] ) && is_array( $args['template'] ) ? $args['template'] : array();
		$template_id    = isset( $args['templateId'] ) ? sanitize_text_field( (string) $args['templateId'] ) : ( isset( $template_input['id'] ) ? sanitize_text_field( (string) $template_input['id'] ) : '' );
		$status         = isset( $args['status'] ) ? sanitize_key( (string) $args['status'] ) : 'processing';
		$order_id       = isset( $args['orderId'] ) ? absint( $args['orderId'] ) : 0;

		$template_data = array(
			'id'      => $template_id,
			'subject' => isset( $template_input['subject'] ) ? (string) $template_input['subject'] : '',
			'heading' => isset( $template_input['heading'] ) ? (string) $template_input['heading'] : '',
			'html'    => isset( $template_input['html'] ) ? (string) $template_input['html'] : '',
			'css'     => isset( $template_input['css'] ) ? (string) $template_input['css'] : '',
		);

		$preview_context = PreviewDataFactory::make(
			$email_id,
			array(
				'order_id' => $order_id,
				'status'   => $status,
				'locale'   => $locale,
				'preview'  => true,
			)
		);

		$start_time = microtime( true );

		$prepared = mail_doctor_prepare_email_template(
			$email_id,
			$order_id,
			array_merge(
				$preview_context,
				array(
					'template'    => $template_data,
					'preview'     => true,
					'locale'      => $locale,
					'email_id'    => $email_id,
					'template_id' => $template_data['id'],
					'render_mode' => $mode,
					'status'      => $status,
					'mode'        => $mode,
				)
			)
		);

		$duration = ( microtime( true ) - $start_time ) * 1000;

		update_option( 'mail_doctor_preview_last_render_ms', round( $duration, 2 ), false );

		if ( empty( $prepared['html'] ) && 'plain' !== $mode ) {
			throw new \RuntimeException( esc_html__( 'Unable to render preview for this template.', 'mail-doctor' ) );
		}

		return array(
			'html'        => 'plain' === $mode ? '' : (string) ( $prepared['html'] ?? '' ),
			'plain_text'  => (string) ( $prepared['plain_text'] ?? '' ),
			'subject'     => (string) ( $prepared['subject'] ?? '' ),
			'heading'     => (string) ( $prepared['heading'] ?? '' ),
			'locale'      => $locale,
			'emailId'     => $email_id,
			'render_time' => round( $duration, 2 ),
			'cache'       => CacheService::diagnostics(),
			'warnings'    => $prepared['warnings'] ?? array(),
		);
	}
}
