<?php

namespace SugarCalendarBookings\Admin\Settings;

use DateTime;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Support\Admin\AbstractTabPage;
use SugarCalendarBookings\Support\Admin\Notices;
use SugarCalendarBookings\Availability\DateOverridesService;
use SugarCalendarBookings\Support\Data\DateTime as DateTimeHelper;
use SugarCalendarBookings\Support\DataProcessing\InputProcessor;
use SugarCalendarBookings\Support\Helpers\Date;
use SugarCalendarBookings\Support\Helpers\Time;
use SugarCalendarBookings\Support\Helpers\UI;

/**
 * Availability Settings tab.
 *
 * @since 1.0.0
 */
class AvailabilitySettingsTab extends AbstractTabPage {

	/**
	 * Plugin options instance.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @var Options
	 */
	protected $options;

	/**
	 * Page title.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public static function get_title() {

		return esc_html__( 'Availability', 'sugar-calendar-bookings-scheduling-appointments-lite' );
	}

	/**
	 * Page slug.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public static function get_slug() {

		return 'settings';
	}

	/**
	 * Page view slug.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public static function get_view_slug() {

		return 'availability';
	}

	/**
	 * Priority in menu position.
	 *
	 * @since 1.0.0
	 *
	 * @return int
	 */
	public static function get_priority() {

		return 10;
	}

	/**
	 * Initialize class properties.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 */
	protected function init_properties() {

		$this->options = Plugin::get( Options::class );
	}

	/**
	 * Get the working schedule data.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	protected function get_working_schedule(): array {

		return $this->options->get( 'availability.working_schedule' );
	}

	/**
	 * Save the working schedule data.
	 *
	 * @since 1.4.0
	 *
	 * @param array $converted_data Converted working schedule data.
	 */
	protected function save_working_schedule( array $converted_data ): void {

		$this->options->update( $converted_data );
	}

	/**
	 * Get date overrides.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	protected function get_date_overrides(): array {

		$service = Plugin::get( DateOverridesService::class );

		return $service->get_all();
	}

	/**
	 * Whether the schedule is read-only.
	 *
	 * @since 1.4.0
	 *
	 * @return bool
	 */
	protected function is_read_only(): bool {

		return false;
	}

	/**
	 * Display content after the weekly schedule table.
	 *
	 * Hook point for subclasses to add content (e.g., reset link).
	 *
	 * @since 1.4.0
	 */
	protected function display_after_weekly_schedule() {

		// No-op in base class.
	}

	/**
	 * Display page.
	 *
	 * @since 1.0.0
	 */
	public function display_content() {

		$this->init_properties();

		ob_start();

		// Display heading.
		UI::heading(
			[
				'title'       => esc_html__( 'Set your default availability schedule', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
				'description' => esc_html__( 'This will be the default schedule which will be applied to new services unless they are overridden in service settings', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			]
		);

		// Weekly schedule table.
		$this->display_weekly_schedule_table();

		// Hook point for subclass content after weekly schedule.
		$this->display_after_weekly_schedule();

		// Timezone display block.
		$this->display_timezone_block();

		// Date overrides section.
		$this->display_date_overrides_section();

		UI::form_wrapper( ob_get_clean() );

		// Sidebar container for React components.
		$this->display_sidebar_container();
	}

	/**
	 * Display sidebar container for React components.
	 *
	 * @since 1.1.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 */
	protected function display_sidebar_container() {

		?>
		<div id="sugar-calendar-bookings-sidebar"></div>
		<?php

		// Render confirmation modal.
		UI::confirmation_modal();
	}

	/**
	 * Display timezone information block.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 */
	protected function display_timezone_block() {

		$timezone_display     = Date::get_default_timezone_string();
		$formatted_datetime   = wp_date(
			$this->options->get( 'display.time_format' ) . ', ' . $this->options->get( 'display.date_format' ),
			null,
			Date::get_default_timezone()
		);
		$general_settings_url = add_query_arg(
			[
				'page' => 'sugar-calendar-bookings-settings',
				'view' => 'general',
			],
			admin_url( 'admin.php' )
		) . '#sugar-calendar-bookings-setting-row-display-timezone';

		?>
		<div class="sugar-calendar-bookings-timezone-info">
			<span class="timezone-label">
				<?php esc_html_e( 'Time Zone:', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>

				<span class="timezone-value">
					<?php echo esc_html( $timezone_display ); ?>
				</span>
			</span>
			<span class="datetime-display">
				<?php echo esc_html( $formatted_datetime ); ?>
			</span>
			<a href="<?php echo esc_url( $general_settings_url ); ?>" class="sugar-calendar-bookings-edit-timezone-btn">
				<?php esc_html_e( 'Edit', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>
			</a>
		</div>
		<?php
	}

	/**
	 * Display date overrides section.
	 *
	 * @since 1.1.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 */
	protected function display_date_overrides_section() {

		// Display heading.
		UI::heading(
			[
				'title'       => esc_html__( 'Date Overrides', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
				'description' => esc_html__( 'Set custom schedule or holidays/ days-off for specific days', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			]
		);

		// Display date overrides list.
		$this->display_date_overrides_list();

		// Add Day button.
		?>
		<button type="button" class="sugar-calendar-bookings-add-override-btn">
			<?php UI::svg_icon( 'plus' ); ?>

			<?php esc_html_e( 'Add Day', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>
		</button>
		<?php
	}

	/**
	 * Display date overrides list.
	 *
	 * @since 1.1.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 */
	protected function display_date_overrides_list() {

		$overrides = $this->get_date_overrides();

		?>
		<div class="sugar-calendar-bookings-date-overrides">
			<?php if ( ! empty( $overrides ) ) : ?>
				<?php foreach ( $overrides as $index => $override ) : ?>
					<?php $this->display_date_override_row( $override, $index ); ?>
				<?php endforeach; ?>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Display a single date override row.
	 *
	 * @since 1.1.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @param array $override Override data.
	 * @param int   $index    Override index.
	 */
	protected function display_date_override_row( $override, $index ) {

		$start_date     = $override['start_date'] ?? '';
		$end_date       = $override['end_date'] ?? '';
		$periods        = $override['periods'] ?? [];
		$is_unavailable = empty( $periods );

		// Format date display.
		$date_display = Date::format_date_range( $start_date, $end_date );

		// Format time display.
		$time_display = $is_unavailable ? esc_html__( 'Unavailable', 'sugar-calendar-bookings-scheduling-appointments-lite' ) : Time::format_time_periods( $periods, $this->options->get( 'display.time_format' ) );

		?>
		<div class="sugar-calendar-bookings-override-row<?php echo $is_unavailable ? ' sugar-calendar-bookings-override-row--unavailable' : ''; ?>" data-start-date="<?php echo esc_attr( $start_date ); ?>">
			<div class="override-date">
				<?php echo esc_html( $date_display ); ?>
			</div>
			<div class="override-time-slots">
				<div class="override-time-display">
					<?php echo esc_html( $time_display ); ?>
				</div>
				<div class="override-actions">
					<button type="button" class="override-edit-btn" data-start-date="<?php echo esc_attr( $start_date ); ?>" aria-label="<?php esc_attr_e( 'Edit date override', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>">
						<span class="edit-icon">
							<?php echo UI::svg_icon( 'pen' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
						</span>
					</button>
					<button type="button" class="override-delete-btn" data-start-date="<?php echo esc_attr( $start_date ); ?>" aria-label="<?php esc_attr_e( 'Delete date override', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>">
						<span class="delete-icon">
							<?php echo UI::svg_icon( 'times' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
						</span>
					</button>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Display weekly schedule table.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 */
	protected function display_weekly_schedule_table() {

		$days             = DateTimeHelper::get_week_days();
		$working_schedule = $this->get_working_schedule();
		?>
		<div class="sugar-calendar-bookings-weekly-schedule">
			<?php foreach ( $days as $day_number => $day_name ) : ?>
				<?php
				$day_data       = $this->get_day_data( $working_schedule, $day_number );
				$is_unavailable = empty( $day_data['periods'] );
				?>
				<div class="sugar-calendar-bookings-day-row<?php echo $is_unavailable ? ' sugar-calendar-bookings-day-row--unavailable' : ''; ?>">
					<div class="day-label">
						<?php echo esc_html( $day_name ); ?>
					</div>
					<div class="day-time-slots">
						<?php $this->display_time_slot_selects( $day_data, $day_number ); ?>
					</div>
				</div>
			<?php endforeach; ?>
		</div>
		<?php
	}

	/**
	 * Display time slot select dropdowns for a specific day.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @param array $day_data   Day data with periods from working schedule.
	 * @param int   $day_number Day number (1-7, Monday-Sunday).
	 */
	protected function display_time_slot_selects( $day_data, $day_number ) {

		?>
		<div class="time-slot-container" data-day="<?php echo esc_attr( $day_number ); ?>">
			<?php if ( empty( $day_data['periods'] ) ) : ?>
				<div class="time-select-row">
					<div class="unavailable-label">
						<?php esc_html_e( 'Unavailable', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>
					</div>
					<div class="time-actions">
						<button type="button" class="time-add-btn time-add-btn--plus" data-day="<?php echo esc_attr( $day_number ); ?>">
							<span class="plus-icon"></span>
						</button>
					</div>
				</div>
			<?php else : ?>
				<?php foreach ( $day_data['periods'] as $period_index => $period ) : ?>
					<div class="time-select-row" data-period="<?php echo esc_attr( $period_index ); ?>">
						<div class="time-select-pair">
							<?php
							UI::select_input(
								[
									'id'          => "start_time_{$day_number}_{$period_index}",
									'name'        => [ 'working_schedule', $day_number, 'periods', $period_index, 'start' ],
									'options'     => $this->get_time_options(),
									'value'       => $period['start'] ?? '',
									'label'       => '',
									'description' => '',
									'choicejs'    => true,
									'class'       => 'choicesjs-select--start',
									'data'        => [
										'row-index' => $period_index,
										'day'       => $day_number,
									],
								]
							);
							?>
							<span class="time-separator">-</span>
							<?php
							UI::select_input(
								[
									'id'          => "end_time_{$day_number}_{$period_index}",
									'name'        => [ 'working_schedule', $day_number, 'periods', $period_index, 'end' ],
									'options'     => $this->get_time_options(),
									'value'       => $period['end'] ?? '',
									'label'       => '',
									'description' => '',
									'choicejs'    => true,
									'class'       => 'choicesjs-select--end',
									'data'        => [
										'row-index' => $period_index,
										'day'       => $day_number,
									],
								]
							);
							?>
						</div>
						<div class="time-actions">
							<button type="button" class="time-remove-btn" data-day="<?php echo esc_attr( $day_number ); ?>" data-period="<?php echo esc_attr( $period_index ); ?>">
								<span class="remove-icon"></span>
							</button>
							<button type="button" class="time-add-btn" data-day="<?php echo esc_attr( $day_number ); ?>">
								<span class="plus-icon"></span>
							</button>
						</div>
					</div>
				<?php endforeach; ?>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Generate time options in 15-minute intervals.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @return array Time options array.
	 */
	protected function get_time_options() {

		$time_format = $this->options->get( 'display.time_format' );

		$options = [];
		$start   = 0; // Start at midnight (0 minutes).
		$end     = 1440; // End at midnight next day (1440 minutes = 24 hours).
		$step    = 15; // 15-minute intervals.

		for ( $minutes = $start; $minutes < $end; $minutes += $step ) {
			$hours   = floor( $minutes / 60 );
			$mins    = $minutes % 60;
			$time_24 = sprintf( '%02d:%02d', $hours, $mins );

			// Convert using the configured time format for display.
			$time_24             = sprintf( '%02d:%02d', $hours, $mins );
			$date                = DateTime::createFromFormat( 'H:i', $time_24 );
			$time_formatted      = $date->format( $time_format );
			$options[ $minutes ] = $time_formatted;
		}

		return $options;
	}

	/**
	 * Get day data from working schedule.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @param array $working_schedule Working schedule data.
	 * @param int   $day_number       Day number (1-7, Monday-Sunday).
	 *
	 * @return array Day data with periods.
	 */
	protected function get_day_data( $working_schedule, $day_number ) {

		$regular_schedule = $working_schedule['regular'] ?? [];

		// Find the day data.
		foreach ( $regular_schedule as $day_data ) {
			if ( isset( $day_data['weekday'] ) ) {
				if ( (int) $day_data['weekday'] === (int) $day_number ) {
					return $day_data;
				}
			}
		}

		// Return empty periods if day not found.
		return [
			'type'    => 'weekday',
			'weekday' => $day_number,
			'periods' => [],
		];
	}

	/**
	 * Get post data processing rules.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_post_data_processing_rules() {

		return [
			'working_schedule.*.periods'         => 'required|array|min:1',
			'working_schedule.*.periods.*.start' => 'required|numeric|min:0,max:1439',
			'working_schedule.*.periods.*.end'   => 'required|numeric|min:0,max:1439',
		];
	}

	/**
	 * Handle POST requests.
	 *
	 * @since 1.0.0
	 *
	 * @param array $post_data Post data.
	 */
	public function handle_post( $post_data = [] ) {

		// Initialize properties to access options.
		$this->init_properties();

		if ( $this->is_read_only() ) {
			return;
		}

		// Convert form data to internal working schedule structure.
		$converted_data = $this->convert_form_data_to_working_schedule( $post_data );

		$this->save_working_schedule( $converted_data );

		Plugin::get( Notices::class )->success( esc_html__( 'Settings successfully saved.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
	}

	/**
	 * Convert form data to working schedule structure.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @param array $post_data Post data from form.
	 *
	 * @return array Converted data structure.
	 */
	protected function convert_form_data_to_working_schedule( $post_data ) {

		$regular_schedule = [];
		$working_schedule = $post_data['working_schedule'] ?? [];

		// Process each day (1-7, Monday-Sunday).
		for ( $day = 1; $day <= 7; $day++ ) {
			$day_data    = $working_schedule[ $day ] ?? [];
			$day_periods = $this->process_day_periods( $day_data['periods'] ?? [] );

			// Always add the day, even with empty periods.
			$regular_schedule[] = [
				'type'    => 'weekday',
				'weekday' => $day,
				'periods' => $day_periods,
			];
		}

		return [
			'availability' => [
				'working_schedule' => [
					'regular' => $regular_schedule,
				],
			],
		];
	}

	/**
	 * Process periods for a single day.
	 *
	 * @since 1.0.0
	 * @since 1.4.0 Changed visibility from private to protected.
	 *
	 * @param array $periods Raw periods data for a day.
	 *
	 * @return array Processed periods array.
	 */
	protected function process_day_periods( $periods ) {

		if ( ! is_array( $periods ) ) {
			return [];
		}

		$day_periods = [];

		foreach ( $periods as $period ) {
			if ( ! isset( $period['start'], $period['end'] ) ) {
				continue;
			}

			$start = (int) $period['start'];
			$end   = (int) $period['end'];

			// Only add valid periods where end > start.
			if ( $end > $start ) {
				$day_periods[] = [
					'start' => $start,
					'end'   => $end,
				];
			}
		}

		// Always return an array, even if empty.
		return $day_periods;
	}

	/**
	 * Get script data for the availability settings page.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function get_script_data() {

		$this->init_properties();

		return [
			'time_options' => $this->get_time_options(),
		];
	}
}
