<?php

namespace SugarCalendarBookings\Availability;

use DateTimeImmutable;
use DateTimeZone;
use Exception;
use WP_Error;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Support\Ajax\AbstractController;
use SugarCalendarBookings\Availability\DateOverridesService;

/**
 * Date Overrides Controller.
 *
 * Handles AJAX requests for managing date overrides in global availability settings.
 *
 * @since 1.1.0
 */
class DateOverridesController extends AbstractController {

	/**
	 * Validate that the current user has the required capabilities.
	 *
	 * @since 1.4.0
	 *
	 * @param string $message Error message if validation fails.
	 */
	protected function validate_capabilities( string $message ): void {

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( $message );
		}
	}

	/**
	 * Handle date override creation request.
	 *
	 * @since 1.1.0
	 */
	public function create() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$this->validate_capabilities(
			esc_html__( 'You are not allowed to create date overrides.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
		);

		$data = $this->get_input_data(
			[
				'start_date'      => 'required|string',
				'end_date'        => 'required|string',
				'periods'         => 'array',
				'periods.*.start' => 'required|numeric|min:0|max:1439',
				'periods.*.end'   => 'required|numeric|min:0|max:1439',
			]
		);

		// Ensure periods is an array.
		if ( ! isset( $data['periods'] ) ) {
			$data['periods'] = [];
		}

		// Validate dates.
		$start_date = $this->validate_date( $data['start_date'] );
		$end_date   = $this->validate_date( $data['end_date'] );

		if ( ! $start_date || ! $end_date ) {
			wp_send_json_error( esc_html__( 'Invalid date format.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		if ( $start_date > $end_date ) {
			wp_send_json_error( esc_html__( 'Start date must be before or equal to end date.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		// Validate periods.
		$periods = $this->validate_periods( $data['periods'] );

		if ( is_wp_error( $periods ) ) {
			wp_send_json_error( $periods->get_error_message() );
		}

		// Get current overrides.
		$overrides = $this->get_overrides();

		// Create new override.
		$new_override = [
			'type'       => 'date_range',
			'start_date' => $start_date->format( 'Y-m-d' ),
			'end_date'   => $end_date->format( 'Y-m-d' ),
			'periods'    => $periods,
		];

		// Add to overrides array.
		$overrides[] = $new_override;

		// Sort overrides by start date.
		$service   = Plugin::get( DateOverridesService::class );
		$overrides = $service->sort_by_date( $overrides );

		// Update options.
		$this->save_overrides( $overrides );

		wp_send_json_success( $new_override );
	}

	/**
	 * Handle date override update request.
	 *
	 * @since 1.1.0
	 */
	public function update() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$this->validate_capabilities(
			esc_html__( 'You are not allowed to update date overrides.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
		);

		$data = $this->get_input_data(
			[
				'original_start_date' => 'required|string',
				'start_date'          => 'required|string',
				'end_date'            => 'required|string',
				'periods'             => 'array',
				'periods.*.start'     => 'required|numeric|min:0|max:1439',
				'periods.*.end'       => 'required|numeric|min:0|max:1439',
			]
		);

		// Ensure periods is an array.
		if ( ! isset( $data['periods'] ) ) {
			$data['periods'] = [];
		}

		// Validate dates.
		$original_start_date = $this->validate_date( $data['original_start_date'] );
		$start_date          = $this->validate_date( $data['start_date'] );
		$end_date            = $this->validate_date( $data['end_date'] );

		if ( ! $original_start_date || ! $start_date || ! $end_date ) {
			wp_send_json_error( esc_html__( 'Invalid date format.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		if ( $start_date > $end_date ) {
			wp_send_json_error( esc_html__( 'Start date must be before or equal to end date.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		// Validate periods.
		$periods = $this->validate_periods( $data['periods'] );

		if ( is_wp_error( $periods ) ) {
			wp_send_json_error( $periods->get_error_message() );
		}

		// Get current overrides.
		$overrides = $this->get_overrides();

		// Find override by original start date.
		$index = array_search( $original_start_date->format( 'Y-m-d' ), array_column( $overrides, 'start_date' ), true );

		if ( $index === false ) {
			wp_send_json_error( esc_html__( 'Date override not found. It may have been deleted. Please refresh the page.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		// Update override.
		$overrides[ $index ] = [
			'type'       => 'date_range',
			'start_date' => $start_date->format( 'Y-m-d' ),
			'end_date'   => $end_date->format( 'Y-m-d' ),
			'periods'    => $periods,
		];

		// Sort overrides by start date.
		$service   = Plugin::get( DateOverridesService::class );
		$overrides = $service->sort_by_date( $overrides );

		// Update options.
		$this->save_overrides( $overrides );

		wp_send_json_success( $overrides[ $index ] );
	}

	/**
	 * Handle date override deletion request.
	 *
	 * @since 1.1.0
	 */
	public function delete() {

		$this->validate_capabilities(
			esc_html__( 'You are not allowed to delete date overrides.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
		);

		$data = $this->get_input_data(
			[
				'start_date' => 'required|string',
			]
		);

		// Validate start date.
		$start_date = $this->validate_date( $data['start_date'] );

		if ( ! $start_date ) {
			wp_send_json_error( esc_html__( 'Invalid date format.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		// Get current overrides.
		$overrides = $this->get_overrides();

		// Find override by start date.
		$index = array_search( $start_date->format( 'Y-m-d' ), array_column( $overrides, 'start_date' ), true );

		if ( $index === false ) {
			wp_send_json_error( esc_html__( 'Date override not found. It may have been deleted. Please refresh the page.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		// Remove override.
		unset( $overrides[ $index ] );

		// Re-index array.
		$overrides = array_values( $overrides );

		// Update options.
		$this->save_overrides( $overrides );

		wp_send_json_success();
	}

	/**
	 * Get all date overrides.
	 *
	 * @since 1.1.0
	 */
	public function get_all() {

		$this->validate_capabilities(
			esc_html__( 'You are not allowed to view date overrides.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
		);

		$service   = Plugin::get( DateOverridesService::class );
		$overrides = $service->get_all();

		wp_send_json_success( $overrides );
	}

	/**
	 * Get create form data.
	 *
	 * @since 1.1.0
	 */
	public function get_create_form_data() {

		$this->validate_capabilities(
			esc_html__( 'You are not allowed to create date overrides.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
		);

		$service   = Plugin::get( DateOverridesService::class );
		$options   = Plugin::get( Options::class );
		$overrides = $service->get_all();

		wp_send_json_success(
			[
				'overrides'     => $overrides,
				'time_format'   => $options->get( 'display.time_format' ),
				'start_of_week' => $options->get( 'display.start_of_week' ),
			]
		);
	}

	/**
	 * Get edit form data for a specific date override.
	 *
	 * @since 1.1.0
	 */
	public function get_edit_form_data() {

		$this->validate_capabilities(
			esc_html__( 'You are not allowed to view date overrides.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
		);

		$data = $this->get_input_data(
			[
				'start_date' => 'required|string',
			]
		);

		// Validate start date.
		$start_date = $this->validate_date( $data['start_date'] );

		if ( ! $start_date ) {
			wp_send_json_error( esc_html__( 'Invalid date format.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		$service   = Plugin::get( DateOverridesService::class );
		$options   = Plugin::get( Options::class );
		$overrides = $service->get_all();

		// Find override by start date.
		$index = array_search( $start_date->format( 'Y-m-d' ), array_column( $overrides, 'start_date' ), true );

		if ( $index === false ) {
			wp_send_json_error( esc_html__( 'Date override not found. It may have been deleted. Please refresh the page.', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
		}

		wp_send_json_success(
			[
				'override'      => $overrides[ $index ],
				'overrides'     => $overrides,
				'time_format'   => $options->get( 'display.time_format' ),
				'start_of_week' => $options->get( 'display.start_of_week' ),
			]
		);
	}

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

		$options          = Plugin::get( Options::class );
		$working_schedule = $options->get( 'availability.working_schedule', [] );

		return $working_schedule['overrides'] ?? [];
	}

	/**
	 * Save the date overrides.
	 *
	 * @since 1.4.0
	 *
	 * @param array $overrides The overrides array to save.
	 */
	protected function save_overrides( array $overrides ): void {

		$options = Plugin::get( Options::class );

		$options->update(
			[
				'availability' => [
					'working_schedule' => [
						'overrides' => $overrides,
					],
				],
			]
		);
	}

	/**
	 * Validate date string.
	 *
	 * @since 1.1.0
	 *
	 * @param string $date_string Date string.
	 *
	 * @return DateTimeImmutable|null
	 */
	protected function validate_date( $date_string ) {

		try {
			$date = new DateTimeImmutable( $date_string, new DateTimeZone( 'UTC' ) );

			return $date;
		} catch ( Exception $e ) {
			return null;
		}
	}

	/**
	 * Validate periods array.
	 *
	 * @since 1.1.0
	 *
	 * @param array $periods Periods array.
	 *
	 * @return array|WP_Error
	 */
	protected function validate_periods( $periods ) {

		$validated_periods = [];

		foreach ( $periods as $period ) {
			$start = (int) $period['start'];
			$end   = (int) $period['end'];

			// Validate time range.
			if ( $start >= $end ) {
				return new WP_Error(
					'invalid_period',
					esc_html__( 'Period start time must be before end time.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
				);
			}

			// Check for overlaps with existing periods.
			foreach ( $validated_periods as $existing_period ) {
				if (
					( $start >= $existing_period['start'] && $start < $existing_period['end'] ) ||
					( $end > $existing_period['start'] && $end <= $existing_period['end'] ) ||
					( $start <= $existing_period['start'] && $end >= $existing_period['end'] )
				) {
					return new WP_Error(
						'overlapping_periods',
						esc_html__( 'Time periods cannot overlap.', 'sugar-calendar-bookings-scheduling-appointments-lite' )
					);
				}
			}

			$validated_periods[] = [
				'start' => $start,
				'end'   => $end,
			];
		}

		// Sort periods by start time.
		usort(
			$validated_periods,
			function ( $a, $b ) {
				return $a['start'] - $b['start'];
			}
		);

		return $validated_periods;
	}
}
