<?php
/**
 * Frontend: Time To Deliver dropdown on Checkout (classic + blocks).
 *
 * Adds a minimal, modern dropdown to the top of WooCommerce checkout forms
 * when Delivery > Time To Deliver is enabled. Time slots sync with delivery
 * opening hours (including custom hours) and are generated using the configured
 * breakdown minutes.
 *
 * Pickup integration is intentionally omitted for this phase.
 *
 * @package FoodOrd
 */

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

/**
 * Class Foodord_Time_To_Deliver_Frontend
 */
class Foodord_Time_To_Deliver_Frontend {
	/**
	 * Bootstrap hooks (frontend only).
	 */
	public function init(): void {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ), 30 );
		// Classic (shortcode) checkout: inject inside the form top.
		add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'render_classic_slot' ), 5 );
	}

	/**
	 * Enqueue JS on checkout when feature is enabled and mode is delivery.
	 */
	public function enqueue_assets(): void {
		if ( is_admin() ) {
			return;
		}
		if ( foodord_is_table_ordering_request() ) {
			return;
		}

		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
			return;
		}

		// Check if the time to deliver feature is enabled.
		$enabled = ( 'yes' === get_option( 'foodord_time_to_deliver_enabled', 'no' ) );
		if ( ! $enabled ) {
			return;
		}

		// Do not display in pickup mode.
		if ( $this->is_pickup_mode() ) {
			return;
		}

		$scheduled    = $this->get_scheduled_date_settings();
		$initial_date = $scheduled['min_date'];
		if ( $scheduled['enabled'] ) {
			$initial_date = $this->get_initial_scheduled_date( 'foodord_delivery_date', $scheduled );
		}
		$is_today = ( $initial_date === $scheduled['min_date'] );

		// Localize computed slots to JS.
		$slots = $is_today ? $this->compute_today_delivery_slots() : $this->compute_delivery_slots_for_date( $initial_date );

		$allow_asap       = false;
		$preorder_enabled = false;
		$preorder_open    = false;
		$is_open          = false;
		if ( class_exists( 'Foodord_Business_Hours' ) ) {
			$status = Foodord_Business_Hours::get_status_payload();
			if ( isset( $status['modes']['delivery'] ) && is_array( $status['modes']['delivery'] ) ) {
				$mode_status = $status['modes']['delivery'];
				if ( isset( $mode_status['is_open'] ) ) {
					$is_open = (bool) $mode_status['is_open'];
				}
				if ( isset( $mode_status['regular_open'] ) ) {
					$allow_asap = (bool) $mode_status['regular_open'];
				}
				if ( ! empty( $mode_status['manual_locked'] ) || ! empty( $mode_status['custom_closed'] ) ) {
					$allow_asap = false;
				}
				if ( isset( $mode_status['preorder_enabled'] ) ) {
					$preorder_enabled = (bool) $mode_status['preorder_enabled'];
				}
				if ( isset( $mode_status['preorder_open'] ) ) {
					$preorder_open = (bool) $mode_status['preorder_open'];
				}
			}
		}

		wp_enqueue_script(
			'foodord-time-to-deliver',
			defined( 'FOODORD_URL' ) ? FOODORD_URL . 'public/js/foodord-time-to-deliver.js' : plugin_dir_url( __FILE__ ) . 'js/foodord-time-to-deliver.js',
			array(),
			FOODORD_VERSION,
			true
		);

		$average_delivery_time = (int) get_option( 'foodord_average_delivery_time', 30 );

		if ( ! $is_today ) {
			$allow_asap       = false;
			$preorder_enabled = false;
			$preorder_open    = false;
			$is_open          = false;
		}

		wp_localize_script(
			'foodord-time-to-deliver',
			'foodord_ttd',
			array(
				'enabled'              => true,
				'mode'                 => 'delivery',
				'options'              => isset( $slots['options'] ) ? $slots['options'] : array(),
				'averageDeliveryTime'  => $average_delivery_time,
				'scheduledDateEnabled' => ! empty( $scheduled['enabled'] ),
				'scheduledDate'        => $initial_date,
				'scheduledDateMin'     => $scheduled['min_date'],
				'scheduledDateMax'     => $scheduled['max_date'],
				'scheduledDateMaxDays' => (int) $scheduled['max_days'],
				'scheduledDateOptions' => $this->build_scheduled_date_options( $scheduled ),
				'labels'               => array(
					'label'       => esc_html__( 'Delivery time', 'foodord' ),
					'dateLabel'   => esc_html__( 'Delivery date', 'foodord' ),
					'today'       => esc_html__( 'Today', 'foodord' ),
					'asap'        => esc_html__( 'As soon as possible', 'foodord' ),
					'closed'      => esc_html__( 'Restaurant is currently closed.', 'foodord' ),
					'closedDate'  => esc_html__( 'Closed', 'foodord' ),
					'noSlots'     => esc_html__( 'No time slots available for selected date.', 'foodord' ),
					'invalidDate' => esc_html__( 'Please select a valid date.', 'foodord' ),
				),
				'isOpen'               => $is_open,
				'allowAsap'            => $allow_asap,
				'preorderEnabled'      => $preorder_enabled,
				'preorderOpen'         => $preorder_open,
				'ajaxUrl'              => admin_url( 'admin-ajax.php' ),
				'nonce'                => wp_create_nonce( 'foodord_delivery_time' ),
				'nonceDate'            => wp_create_nonce( 'foodord_delivery_date' ),
				'nonceSlots'           => wp_create_nonce( 'foodord_delivery_slots' ),
			)
		);
	}

	/**
	 * Classic checkout: output a mount point at top of the form.
	 */
	public function render_classic_slot(): void {
		if ( is_admin() ) {
			return;
		}
		if ( foodord_is_table_ordering_request() ) {
			return;
		}

		// Respect same conditions as enqueue to avoid stray markup.
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
			return;
		}
		if ( 'yes' !== get_option( 'foodord_time_to_deliver_enabled', 'no' ) ) {
			return;
		}
		if ( $this->is_pickup_mode() ) {
			return;
		}

		$scheduled    = $this->get_scheduled_date_settings();
		$initial_date = $scheduled['min_date'];
		if ( $scheduled['enabled'] ) {
			$initial_date = $this->get_initial_scheduled_date( 'foodord_delivery_date', $scheduled );
		}
		?>
		<div id="foodord-ttd" class="foodord-ttd" role="group" aria-label="<?php echo esc_attr__( 'Delivery time', 'foodord' ); ?>">
			<?php if ( ! empty( $scheduled['enabled'] ) ) : ?>
				<div class="foodord-ttd__label-group">
					<label class="foodord-ttd__label" for="foodord-ttd-date"><?php echo esc_html__( 'Delivery date', 'foodord' ); ?></label>
					<select class="foodord-ttd__date" id="foodord-ttd-date" name="foodord_delivery_date" autocomplete="off"></select>
				</div>
			<?php endif; ?>
			<div class="foodord-ttd__label-group">
				<label class="foodord-ttd__label" for="foodord-ttd-select"><?php echo esc_html__( 'Delivery time', 'foodord' ); ?></label>
				<select class="foodord-ttd__select" id="foodord-ttd-select" name="foodord_delivery_time" autocomplete="off"></select>
			</div>
		</div>
		<?php
	}

	/**
	 * Compute today's delivery time slots using opening hours and breakdown.
	 *
	 * @return array { opening, closing, breakdown, options[] }
	 */
	private function compute_today_delivery_slots(): array {
		$default_breakdown = (int) get_option( 'foodord_time_to_deliver_breakdown', '30' );
		if ( $default_breakdown < 1 ) {
			$default_breakdown = 30;
		}

		if ( ! class_exists( 'Foodord_Business_Hours' ) ) {
			return array(
				'opening'   => '',
				'closing'   => '',
				'breakdown' => $default_breakdown,
				'options'   => array(),
			);
		}

		$slots = Foodord_Business_Hours::get_mode_slots( 'delivery' );

		$opening   = isset( $slots['opening'] ) ? (string) $slots['opening'] : '';
		$closing   = isset( $slots['closing'] ) ? (string) $slots['closing'] : '';
		$breakdown = isset( $slots['breakdown'] ) ? (int) $slots['breakdown'] : $default_breakdown;
		$options   = isset( $slots['options'] ) && is_array( $slots['options'] ) ? $slots['options'] : array();

		return array(
			'opening'   => $opening,
			'closing'   => $closing,
			'breakdown' => $breakdown,
			'options'   => $options,
		);
	}

	/**
	 * Compute delivery time slots for a specific calendar date (YYYY-MM-DD).
	 * Uses the slot engine with a reference at start-of-day.
	 *
	 * @param string $date Calendar date (YYYY-MM-DD).
	 * @return array { opening, closing, breakdown, options[] }
	 */
	private function compute_delivery_slots_for_date( string $date ): array {
		$default_breakdown = (int) get_option( 'foodord_time_to_deliver_breakdown', '30' );
		if ( $default_breakdown < 1 ) {
			$default_breakdown = 30;
		}

		if ( ! class_exists( 'Foodord_Business_Hours' ) ) {
			return array(
				'opening'   => '',
				'closing'   => '',
				'breakdown' => $default_breakdown,
				'options'   => array(),
			);
		}

		try {
			$ref = new DateTimeImmutable( $date . ' 00:00:00', wp_timezone() );
		} catch ( Exception $e ) {
			unset( $e );
			return array(
				'opening'   => '',
				'closing'   => '',
				'breakdown' => $default_breakdown,
				'options'   => array(),
			);
		}

		$slots = Foodord_Business_Hours::get_mode_slots( 'delivery', $ref, false );

		$opening   = isset( $slots['opening'] ) ? (string) $slots['opening'] : '';
		$closing   = isset( $slots['closing'] ) ? (string) $slots['closing'] : '';
		$breakdown = isset( $slots['breakdown'] ) ? (int) $slots['breakdown'] : $default_breakdown;
		$options   = isset( $slots['options'] ) && is_array( $slots['options'] ) ? $slots['options'] : array();

		return array(
			'opening'   => $opening,
			'closing'   => $closing,
			'breakdown' => $breakdown,
			'options'   => $options,
		);
	}

	/**
	 * Get scheduled date feature settings.
	 *
	 * @return array{enabled: bool, max_days: int, min_date: string, max_date: string}
	 */
	private function get_scheduled_date_settings(): array {
		$enabled  = ( 'yes' === get_option( 'foodord_scheduled_date_enabled_delivery', 'no' ) );
		$max_days = absint( get_option( 'foodord_scheduled_date_max_days_delivery', 7 ) );
		if ( $max_days < 1 || $max_days > 365 ) {
			$max_days = 7;
		}

		$timezone = wp_timezone();
		$today    = wp_date( 'Y-m-d', time(), $timezone );
		$max_date = $today;
		try {
			$max_dt   = new DateTimeImmutable( $today, $timezone );
			$max_dt   = $max_dt->modify( '+' . $max_days . ' days' );
			$max_date = $max_dt->format( 'Y-m-d' );
		} catch ( Exception $e ) {
			unset( $e );
			$max_date = $today;
		}

		return array(
			'enabled'  => $enabled,
			'max_days' => $max_days,
			'min_date' => $today,
			'max_date' => $max_date,
		);
	}

	/**
	 * Build scheduled date dropdown options.
	 *
	 * @param array{enabled: bool, max_days: int, min_date: string, max_date: string} $settings Settings.
	 * @return array<int, array{value: string, label: string, isToday: bool, disabled: bool}>
	 */
	private function build_scheduled_date_options( array $settings ): array {
		if ( empty( $settings['enabled'] ) ) {
			return array();
		}

		$max_days = isset( $settings['max_days'] ) ? absint( $settings['max_days'] ) : 0;
		if ( $max_days < 1 || $max_days > 365 ) {
			$max_days = 7;
		}

		$timezone = wp_timezone();
		$format   = (string) get_option( 'date_format' );
		if ( '' === trim( $format ) ) {
			$format = 'F j, Y';
		}

		try {
			$base = new DateTimeImmutable( (string) $settings['min_date'] . ' 00:00:00', $timezone );
		} catch ( Exception $e ) {
			unset( $e );
			return array();
		}

		$max_date = (string) $settings['max_date'];

		$options = array();
		for ( $i = 0; $i <= $max_days; $i++ ) {
			try {
				$dt = $base->modify( '+' . $i . ' days' );
			} catch ( Exception $e ) {
				unset( $e );
				continue;
			}

			$value = $dt->format( 'Y-m-d' );
			if ( '' === $value ) {
				continue;
			}
			if ( '' !== $max_date && $value > $max_date ) {
				break;
			}

			$options[] = array(
				'value'    => $value,
				'label'    => wp_date( $format, $dt->getTimestamp(), $timezone ),
				'isToday'  => ( 0 === $i ),
				'disabled' => $this->is_scheduled_date_custom_closed( $value ),
			);
		}

		return $options;
	}

	/**
	 * Determine whether a scheduled delivery date is closed by custom hours.
	 *
	 * @param string $date Date string.
	 * @return bool
	 */
	private function is_scheduled_date_custom_closed( string $date ): bool {
		if ( ! class_exists( 'Foodord_Business_Hours' ) ) {
			return false;
		}
		if ( ! method_exists( 'Foodord_Business_Hours', 'get_custom_entry_for_date' ) ) {
			return false;
		}

		try {
			$day = new DateTimeImmutable( $date . ' 00:00:00', wp_timezone() );
		} catch ( Exception $e ) {
			unset( $e );
			return false;
		}

		$custom_entry = Foodord_Business_Hours::get_custom_entry_for_date( 'delivery', $day );
		return is_array( $custom_entry ) && ! empty( $custom_entry['closed'] );
	}

	/**
	 * Get the first scheduled delivery date not closed by custom hours.
	 *
	 * @param array{enabled: bool, max_days: int, min_date: string, max_date: string} $settings Settings.
	 * @return string
	 */
	private function get_first_available_scheduled_date( array $settings ): string {
		$min_date = (string) $settings['min_date'];
		$max_days = isset( $settings['max_days'] ) ? absint( $settings['max_days'] ) : 0;
		if ( $max_days < 1 || $max_days > 365 ) {
			$max_days = 7;
		}

		try {
			$base = new DateTimeImmutable( $min_date . ' 00:00:00', wp_timezone() );
		} catch ( Exception $e ) {
			unset( $e );
			return $min_date;
		}

		$max_date = (string) $settings['max_date'];
		for ( $i = 0; $i <= $max_days; $i++ ) {
			$value = $base->modify( '+' . $i . ' days' )->format( 'Y-m-d' );
			if ( '' !== $max_date && $value > $max_date ) {
				break;
			}
			if ( ! $this->is_scheduled_date_custom_closed( $value ) ) {
				return $value;
			}
		}

		return $min_date;
	}

	/**
	 * Get initial scheduled date (session fallback).
	 *
	 * @param string $session_key WooCommerce session key.
	 * @param array  $settings Scheduled date settings.
	 * @return string
	 */
	private function get_initial_scheduled_date( string $session_key, array $settings ): string {
		if ( empty( $settings['enabled'] ) ) {
			return (string) $settings['min_date'];
		}

		if ( ! function_exists( 'WC' ) || ! WC()->session ) {
			return (string) $settings['min_date'];
		}

		$candidate = (string) WC()->session->get( $session_key, '' );
		if (
			$this->is_valid_scheduled_date( $candidate, (string) $settings['min_date'], (string) $settings['max_date'] )
			&& ! $this->is_scheduled_date_custom_closed( $candidate )
		) {
			return $candidate;
		}

		return $this->get_first_available_scheduled_date( $settings );
	}

	/**
	 * Validate scheduled date string (YYYY-MM-DD) and range.
	 *
	 * @param string $date Candidate date.
	 * @param string $min Minimum date.
	 * @param string $max Maximum date.
	 * @return bool
	 */
	private function is_valid_scheduled_date( string $date, string $min, string $max ): bool {
		if ( '' === $date ) {
			return false;
		}
		if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ) {
			return false;
		}
		return ( $date >= $min && $date <= $max );
	}

	/**
	 * Detect whether current order mode is pickup.
	 */
	private function is_pickup_mode(): bool {
		if ( function_exists( 'foodord_get_order_mode' ) ) {
			return ( 'pickup' === foodord_get_order_mode() );
		}
		if ( function_exists( 'WC' ) && WC()->session ) {
			$mode = (string) WC()->session->get( 'foodord_order_mode', 'delivery' );
			if ( in_array( $mode, array( 'delivery', 'pickup' ), true ) ) {
				return ( 'pickup' === $mode );
			}
		}
		return false;
	}

	/**
	 * Debug helper that logs when WP_DEBUG is enabled.
	 *
	 * @param string $message  Message to log.
	 * @param array  $context  Extra context for the message.
	 */
}
