<?php

namespace SugarCalendarBookings\BookingForm;

use SugarCalendarBookings\Admin\Assets;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Services\ServiceModel;
use SugarCalendarBookings\Support\Shortcodes\AbstractShortcode;

/**
 * Booking Form Shortcode.
 *
 * Handles the registration and rendering of the [sugar_calendar_bookings_form] shortcode.
 * Reuses the BookingFormBlock rendering logic for consistency.
 *
 * @since 1.0.0
 */
class BookingFormShortcode extends AbstractShortcode {

	/**
	 * Get the shortcode name (tag).
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public function get_shortcode_name(): string {

		return 'sugar_calendar_bookings_form';
	}

	/**
	 * Build the booking-form shortcode string for a given service.
	 *
	 * Pass a ServiceModel to preselect that service via `service_id`; pass
	 * null to emit the bare shortcode so the form's built-in service picker
	 * is used instead.
	 *
	 * @since 1.5.0
	 *
	 * @param ServiceModel|null $service Service to preselect, or null for the picker.
	 *
	 * @return string
	 */
	public static function for_service( ?ServiceModel $service ): string {

		if ( $service === null ) {
			return '[sugar_calendar_bookings_form]';
		}

		return sprintf( '[sugar_calendar_bookings_form service_id="%d"]', (int) $service->id );
	}

	/**
	 * Get the default shortcode attributes.
	 *
	 * These are the shortcode attribute names (snake_case) with their default values.
	 * They will be normalized to match block format (camelCase) in normalize_attributes().
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_default_attributes(): array {

		return [
			'service_id'               => '',
			'show_service_image'       => 'true',
			'show_service_description' => 'true',
			'time_slot_layout'         => '2-column',
			'form_appearance'          => 'light',
			'hide_branding'            => 'false',
		];
	}

	/**
	 * Display the shortcode output.
	 *
	 * @since 1.0.0
	 *
	 * @param array  $attributes Shortcode attributes.
	 * @param string $content    Shortcode content.
	 * @param string $tag        Shortcode tag.
	 *
	 * @return string Shortcode HTML output.
	 */
	public function display( array $attributes, string $content, string $tag ): string {

		// Merge with default attributes.
		$attributes = shortcode_atts( $this->get_default_attributes(), $attributes, $tag );

		// Normalize attributes to match block format.
		$normalized_attributes = $this->normalize_attributes( $attributes );

		// Get service IDs from shortcode attributes.
		$service_ids = $normalized_attributes['services'];

		// Get booking form data using the same service as the block.
		$booking_form_data = Plugin::get( BookingFormService::class )->get_booking_form_data( $service_ids );

		// Add the booking form data to attributes for the markup.
		$normalized_attributes['initialData'] = $booking_form_data;

		// Enqueue frontend assets.
		$this->enqueue_frontend_assets();

		// Render the shortcode markup.
		ob_start();
		$this->render_markup( $normalized_attributes );

		return ob_get_clean();
	}

	/**
	 * Normalize shortcode attributes to match block format.
	 *
	 * Converts snake_case shortcode attributes to camelCase block attributes
	 * with correct types and validated values to match block.json exactly.
	 *
	 * @since 1.0.0
	 *
	 * @param array $attributes Raw shortcode attributes.
	 *
	 * @return array Normalized attributes matching block.json structure.
	 */
	private function normalize_attributes( array $attributes ): array { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		// Parse service IDs from comma-separated string.
		$services = [];

		if ( ! empty( $attributes['service_id'] ) ) {
			$services = array_map( 'intval', explode( ',', $attributes['service_id'] ) );
			$services = array_filter( $services );
		}

		// Convert string boolean values to actual booleans.
		$show_service_image = ! empty( $attributes['show_service_image'] )
			? filter_var( $attributes['show_service_image'], FILTER_VALIDATE_BOOLEAN )
			: true;

		$show_service_description = ! empty( $attributes['show_service_description'] )
			? filter_var( $attributes['show_service_description'], FILTER_VALIDATE_BOOLEAN )
			: true;

		$hide_branding = ! empty( $attributes['hide_branding'] )
			? filter_var( $attributes['hide_branding'], FILTER_VALIDATE_BOOLEAN )
			: false;

		// Validate enum values against block.json constraints.
		$time_slot_layout = in_array( $attributes['time_slot_layout'], [ '2-column', '3-column' ], true )
			? $attributes['time_slot_layout']
			: '2-column';

		$form_appearance = in_array( $attributes['form_appearance'], [ 'light', 'dark', 'auto' ], true )
			? $attributes['form_appearance']
			: 'light';

		// Return attributes with exact camelCase names from block.json.
		return [
			'services'               => $services,
			'showServiceImage'       => $show_service_image,
			'showServiceDescription' => $show_service_description,
			'timeSlotLayout'         => $time_slot_layout,
			'formAppearance'         => $form_appearance,
			'hideBranding'           => $hide_branding,
		];
	}

	/**
	 * Enqueue frontend assets for the shortcode.
	 *
	 * Note: Scripts are registered and localized globally via BookingFormAssets class.
	 *
	 * @since 1.0.0
	 * @since 1.5.0 Enqueue antispam captcha script when a provider is configured.
	 */
	private function enqueue_frontend_assets(): void {

		$assets = Plugin::get( Assets::class );

		if ( $assets->is_dev() ) {
			$assets->enqueue_dev_runtime();
		}

		// Enqueue the globally registered scripts.
		wp_enqueue_script( 'react-jsx-runtime' );
		wp_enqueue_script( 'scbookings-booking-form-script' );
		wp_enqueue_style( 'scbookings-booking-form-style' );

		// Enqueue antispam captcha script if a provider is configured.
		Plugin::get( BookingFormAssets::class )->enqueue_antispam_third_party_script();
	}

	/**
	 * Render the shortcode markup.
	 *
	 * @since 1.0.0
	 *
	 * @param array $attributes Normalized shortcode attributes.
	 */
	private function render_markup( array $attributes ): void {

		// Generate a unique ID for this shortcode instance.
		$wrapper_id = 'scbookings-shortcode-' . uniqid();

		// Create CSS classes for the wrapper.
		$wrapper_classes = [
			'scbookings-sc-bookings-form',
			'scbookings-shortcode-wrapper',
		];

		// Add appearance class.
		if ( ! empty( $attributes['formAppearance'] ) ) {
			$wrapper_classes[] = 'scbookings-appearance-' . $attributes['formAppearance'];
		}

		// Add layout class.
		if ( ! empty( $attributes['timeSlotLayout'] ) ) {
			$wrapper_classes[] = 'scbookings-layout-' . $attributes['timeSlotLayout'];
		}

		$wrapper_class   = implode( ' ', $wrapper_classes );
		$attributes_json = wp_json_encode( $attributes );
		$attributes_data = _wp_specialchars( $attributes_json, ENT_QUOTES, 'UTF-8', true );
		?>
		<div id="<?php echo esc_attr( $wrapper_id ); ?>" class="<?php echo esc_attr( $wrapper_class ); ?>">
			<div
				class="scbookings-sc-bookings-form-container"
				data-block-data="<?php echo $attributes_data; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"
			>
			</div>
		</div>
		<?php
	}
}
