<?php
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * WC_Appointments_Admin_Settings
 */
class WC_Appointments_Admin_Settings extends WC_Settings_Page {

	// Gcal instance.
	public ?WC_Appointments_GCal $gcal = null;

	/**
	 * Setup settings class
	 *
	 * @since  1.0
	 */
	public function __construct() {
		// Appointments Settings ID.
		$this->id    = 'appointments';
		$this->label = __( 'Appointments', 'woocommerce-appointments' );

        add_action( 'woocommerce_admin_field_gcal_authorization', [ $this, 'gcal_authorization_setting' ], 10, 1 );
        add_action( 'woocommerce_admin_field_gcal_calendar_id', [ $this, 'gcal_calendar_id_setting' ], 10, 1 );
        add_action( 'woocommerce_admin_field_manual_sync', [ $this, 'manual_sync_setting' ], 10, 1 );

		// Indexing controls custom field.
		add_action( 'woocommerce_admin_field_indexing_controls', [ $this, 'indexing_controls_setting' ], 10, 0 );

		parent::__construct();
	}

	/**
	 * Get sections
	 *
	 * @return array
	 */
	public function get_sections() {
		$sections = [
			''       => __( 'Global Availability', 'woocommerce-appointments' ),
			'gcal'   => __( 'Google Calendar', 'woocommerce-appointments' ),
			'index'  => __( 'Indexing & Performance', 'woocommerce-appointments' ),
		];

		return apply_filters( 'woocommerce_get_sections_' . $this->id, $sections );
	}

	/**
	 * Output the settings
	 *
	 * @since 1.0
	 */
	public function output(): void {
		global $current_section;

		if ( '' == $current_section ) {
			include __DIR__ . '/views/html-settings-global-availability.php';
		} else {
			wp_enqueue_script( 'wc_appointments_writepanel_js' );
			$settings = $this->get_settings( $current_section );
			WC_Admin_Settings::output_fields( $settings );
		}
	}

	/**
	 * Save settings
	 */
	public function save(): void {
		global $current_section;

		if ( '' == $current_section ) {
			$this->save_global_availability();
		} else {
			$settings = $this->get_settings( $current_section );
			WC_Admin_Settings::save_fields( $settings );
		}

		if ( $current_section ) {
			do_action( 'woocommerce_update_options_' . $this->id . '_' . $current_section );
		}
	}

	/**
	 * Save global availability
	 */
	public function save_global_availability(): void {
		// Save the field values
		if ( ! empty( $_POST['appointments_availability_submitted'] ) ) {

			// Delete.
			if ( ! empty( $_POST['wc_appointment_availability_deleted'] ) ) {
				$deleted_ids = array_filter( explode( ',', wc_clean( wp_unslash( $_POST['wc_appointment_availability_deleted'] ) ) ) );

				foreach ( $deleted_ids as $delete_id ) {
					$availability_object = get_wc_appointments_availability( $delete_id );
					if ( $availability_object ) {
						$availability_object->delete();
					}
				}
			}

			// Save using unified decoder (JSON preferred, arrays fallback).
			$data_store = WC_Data_Store::load( 'appointments-availability' );
			$rules      = $data_store->decode_rules_from_post();
			$rules      = array_values( array_filter( $rules, [ $data_store, 'is_rule_valid' ] ) );
			foreach ( $rules as $i => $rule ) {
					$current_id = empty( $rule['id'] ) ? 0 : intval( $rule['id'] );
					$range_type = empty( $rule['type'] ) ? '' : wc_clean( $rule['type'] );

					$availability = get_wc_appointments_availability( $current_id );
					$availability->set_ordering( intval( $i ) );
					$availability->set_range_type( $range_type );
					$availability->set_kind( WC_Appointments_Availability::KIND_GLOBAL );

					// Apply normalized rule properties.
					$data_store->apply_json_rule_to_availability( $availability, $rule );

					$availability->save();
				}
			do_action( 'wc_appointments_global_availability_on_save' );
		}
	}

	/**
	 * Get settings array.
	 *
	 * @param string $current_section Current section name.
	 * @return array
	 */
	public function get_settings( $current_section = '' ) {
		$settings = [];
		if ( 'gcal' === $current_section ) {
			$settings = apply_filters(
			    'wc_appointments_gcal_settings',
			    [
					[
						'title' => __( 'Google Calendar Sync', 'woocommerce-appointments' ),
						'type'  => 'title',
						'desc'  => sprintf(
							/* translators: %s: link to google calendar sync tutorial */
							__( 'To use this integration go through %s instructions.', 'woocommerce-appointments' ),
						    '<a href="https://docs.bookingwp.com/appointments/setup/google-calendar" target="_blank">' . __( 'Google Calendar Integration', 'woocommerce-appointments' ) . '</a>',
						),
						'id'    => 'wc_appointments_gcal_options',
					],
					[
						'title'             => __( 'Client ID', 'woocommerce-appointments' ),
						'desc'              => __( 'Your Google Client ID.', 'woocommerce-appointments' ),
						'id'                => 'wc_appointments_gcal_client_id',
						'type'              => 'password',
						'class'             => 'password-input',
						'custom_attributes' => [
							'autocomplete' => 'off',
						],
						'default'           => '',
						'autoload'          => false,
						'desc_tip'          => true,
					],
					[
						'title'             => __( 'Client Secret', 'woocommerce-appointments' ),
						'desc'              => __( 'Your Google Client Secret.', 'woocommerce-appointments' ),
						'id'                => 'wc_appointments_gcal_client_secret',
						'type'              => 'password',
						'class'             => 'password-input',
						'custom_attributes' => [
							'autocomplete' => 'off',
						],
						'default'           => '',
						'autoload'          => false,
						'desc_tip'          => true,
					],
					[
						'title' => __( 'Authorization', 'woocommerce-appointments' ),
						'type'  => 'gcal_authorization',
					],
					[
						'title' => __( 'Calendar ID', 'woocommerce-appointments' ),
						'type'  => 'gcal_calendar_id',
						'id'    => 'wc_appointments_gcal_calendar_id',
					],
					'gcal_twoway' => [
						'title'    => __( 'Sync Preference', 'woocommerce-appointments' ),
						'desc'     => __( 'Choose the sync preference.', 'woocommerce-appointments' ),
						'options'  => [
							'one_way' => __( 'One way - from Store to Google', 'woocommerce-appointments' ),
							'two_way' => __( 'Two way - between Store and Google', 'woocommerce-appointments' ),
						],
						'id'       => 'wc_appointments_gcal_twoway',
						'default'  => 'one_way',
						'type'     => 'select',
						'class'    => 'wc-enhanced-select',
						'desc_tip' => true,
					],
					'manual_sync' => [
						'title' => __( 'Last Sync', 'woocommerce-appointments' ),
						'type'  => 'manual_sync',
					],
					[
						'type' => 'sectionend',
						'id'   => 'gcal_twoway_options',
					],
					[
						'title' => __( 'Testing', 'woocommerce-appointments' ),
						'type'  => 'title',
						'desc'  => sprintf(
							/* translators: %s: log file name string */
							__( 'Log Google Calendar events, such as API requests, inside %s', 'woocommerce-appointments' ),
						    '<code>woocommerce/logs/' . $this->id . '-' . sanitize_file_name( wp_hash( $this->id ) ) . '.txt</code>',
						),
						'id'    => 'wc_appointments_gcal_testing',
					],
					[
						'title'   => __( 'Debug Log', 'woocommerce-appointments' ),
						'desc'    => __( 'Enable logging', 'woocommerce-appointments' ),
						'id'      => 'wc_appointments_gcal_debug',
						'default' => 'no',
						'type'    => 'checkbox',
					],
					[
						'type' => 'sectionend',
						'id'   => 'gcal_debug_options',
					],
				],
			);

			// Run Gcal oauth redirect.
			$gcal_integration_class = wc_appointments_gcal();

			// Get access token.
			$access_token = $gcal_integration_class->get_access_token();

            // Get calendar ID.
            $calendar_id = get_option( 'wc_appointments_gcal_calendar_id' );

            // Stop here if access token no active.
            if ( ! $access_token || ! $calendar_id ) {
                unset( $settings['manual_sync'] );
            }

            // Stop here if access token no active.
            if ( ! $access_token ) {
                unset( $settings['gcal_twoway'] );
            }
		} elseif ( 'index' === $current_section ) {
			$settings = [
				[
					'title' => __( 'Indexing & Performance', 'woocommerce-appointments' ),
					'type'  => 'title',
					'desc'  => __( 'Indexing creates a high-performance cached database table of availability slots and appointments for faster booking form responses. This feature significantly improves site performance, especially for complex availability rules or high-traffic booking sites. Once enabled, the system automatically maintains the index by expanding it as time progresses within your caching horizon. Manual re-indexing is only needed to rebuild the entire index from scratch (e.g., after major rule changes).', 'woocommerce-appointments' ),
					'id'    => 'wc_appointments_indexing_options',
				],
				[
					'title'    => __( 'Use Indexed Availability', 'woocommerce-appointments' ),
					'desc'     => __( 'Enable high-performance availability checking using a cached database table.', 'woocommerce-appointments' ),
					'desc_tip' => __( '<p><strong>Performance Enhancement:</strong><br>When enabled, availability checks will use a pre-built indexed table for dramatically faster performance. This creates an additional database table that caches availability slots and existing appointments, significantly improving booking form load times and slot availability checks.</p><p><strong>⚠️ IMPORTANT CONSIDERATIONS:</strong><br>• <em>Database Usage:</em> Creates an additional table that can grow large with many appointments and complex availability rules<br>• <em>Storage Impact:</em> May require significant additional disk space depending on your booking volume and horizon settings<br>• <em>Automatic Maintenance:</em> The system automatically expands the index as time progresses within your caching horizon<br>• <em>Performance Trade-off:</em> Uses more storage for faster query performance</p><p><strong>Especially Beneficial For:</strong><br>• High booking volume sites<br>• Complex availability rules<br>• Multiple staff members<br>• Long booking horizons</p><p><strong>Manual Re-indexing:</strong><br>Only needed when you want to rebuild the entire index from scratch (e.g., after major rule changes). You must enable this option before running the manual re-index process.</p>', 'woocommerce-appointments' ),
					'id'       => 'wc_appointments_use_indexed_cache',
					'default'  => 'no',
					'type'     => 'checkbox',
				],
                'manual_reindex' => [
					'title' => __( 'Manual Re-index', 'woocommerce-appointments' ),
					'type'  => 'indexing_controls',
					'id'    => 'wc_appointments_indexing_controls',
				],
				[
					'title'    => __( 'Caching Horizon', 'woocommerce-appointments' ),
					'desc'     => __( 'How many months ahead to cache availability data for faster lookups.', 'woocommerce-appointments' ),
					'id'       => 'wc_appointments_cache_horizon_months',
					'default'  => '3',
					'type'     => 'select',
					'options'  => [
						'1'  => __( '1 month', 'woocommerce-appointments' ),
						'2'  => __( '2 months', 'woocommerce-appointments' ),
						'3'  => __( '3 months', 'woocommerce-appointments' ),
						'4'  => __( '4 months', 'woocommerce-appointments' ),
						'5'  => __( '5 months', 'woocommerce-appointments' ),
						'6'  => __( '6 months', 'woocommerce-appointments' ),
						'7'  => __( '7 months', 'woocommerce-appointments' ),
						'8'  => __( '8 months', 'woocommerce-appointments' ),
						'9'  => __( '9 months', 'woocommerce-appointments' ),
						'10' => __( '10 months', 'woocommerce-appointments' ),
						'11' => __( '11 months', 'woocommerce-appointments' ),
						'12' => __( '12 months', 'woocommerce-appointments' ),
					],
					'desc_tip' => true,
				],
				[
					'type' => 'sectionend',
					'id'   => 'wc_appointments_indexing_options',
				],
			];
            // Get indexing controls option.
            $reindex_id = 'yes' === get_option( 'wc_appointments_use_indexed_cache', 'no' );

            // Stop here if indexing not enabled.
            if ( ! $reindex_id ) {
                unset( $settings['manual_reindex'] );
            }
		} else {
			$settings = [];
		}

		return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings, $current_section );
	}

	/**
	 * Generate the GCal Authorization field.
	 *
	 * @param  mixed $key
	 * @param  array $data
	 *
	 * @echo string
	 */
	public function gcal_authorization_setting( $data ): void {
		$client_id     = sanitize_text_field( $_POST['wc_appointments_gcal_client_id'] ?? '' ) ?: get_option( 'wc_appointments_gcal_client_id' );
		$client_secret = sanitize_text_field( $_POST['wc_appointments_gcal_client_secret'] ?? '' ) ?: get_option( 'wc_appointments_gcal_client_secret' );

		// Run Gcal oauth redirect.
		$gcal_integration_class = wc_appointments_gcal();

		// Get access token.
		$access_token = $gcal_integration_class->get_access_token();

		ob_start();
		?>
		<tr valign="top">
			<th scope="row" class="titledesc">
				<?php echo wp_kses_post( $data['title'] ); ?>
			</th>
			<td class="forminp">
				<input type="hidden" name="wc_appointments_google_calendar_redirect" id="wc_appointments_google_calendar_redirect">
				<?php if ( ! $access_token && ( $client_id && $client_secret ) ) : ?>
					<button type="button" class="button oauth_redirect" data-staff="0" data-logout="0"><?php esc_html_e( 'Connect with Google', 'woocommerce-appointments' ); ?></button>
				<?php elseif ( $access_token ) : ?>
					<p style="color:green;"><?php esc_html_e( 'Successfully authenticated.', 'woocommerce-appointments' ); ?></p>
					<p class="submit"><button type="button" class="button oauth_redirect" data-staff="0" data-logout="1"><?php esc_html_e( 'Disconnect', 'woocommerce-appointments' ); ?></button></p>
				<?php else : ?>
					<p style="color:red;"><?php esc_html_e( 'Please fill out all required fields from above.', 'woocommerce-appointments' ); ?></p>
				<?php endif; ?>
			</td>
		</tr>
		<?php
		echo ob_get_clean();
	}

	/**
	 * Generate the GCal Authorization field.
	 *
	 * @param  mixed $key
	 * @param  array $data
	 *
	 * @echo string
	 */
	public function gcal_calendar_id_setting( $data ): void {
		$client_id     = get_option( 'wc_appointments_gcal_client_id' );
		$client_secret = get_option( 'wc_appointments_gcal_client_secret' );
		$calendar_id   = get_option( 'wc_appointments_gcal_calendar_id' );

		// Run Gcal oauth redirect.
		$gcal_integration_class = wc_appointments_gcal();

		// Get access token.
		$access_token = $gcal_integration_class->get_access_token();

		// Get calendars array.
		$get_calendars = $gcal_integration_class->get_calendars();

		if ( ! $access_token || ! $client_id || ! $client_secret ) {
			return;
		}

		ob_start();
		?>
		<tr valign="top">
			<th scope="row" class="titledesc">
				<label for="wc_appointments_gcal_calendar_id">
					<?php echo wp_kses_post( $data['title'] ); ?>
					<?php echo wc_help_tip( esc_html__( 'Your Google Calendar ID. Leave empty if you only want to sync on staff level.', 'woocommerce-appointments' ) ); ?>
				</label>
			</th>
			<td class="forminp">
				<?php if ( $get_calendars ) : ?>
					<select id="wc_appointments_gcal_calendar_id" name="wc_appointments_gcal_calendar_id" class="wc-enhanced-select" style="width:25em;">
						<option value=""><?php esc_html_e( 'N/A', 'woocommerce-appointments' ); ?></option>
						<?php
						// Check if authorized.
						if ( $access_token ) {
							foreach ( $get_calendars as $cal_id => $cal_name ) {
							?>
								<option value="<?php esc_attr_e( $cal_id ); ?>" <?php selected( $calendar_id, $cal_id ); ?>><?php esc_attr_e( $cal_name ); ?></option>
							<?php
							}
						}
						?>
					</select>
				<?php else : ?>
					<input type="text" name="wc_appointments_gcal_calendar_id" id="wc_appointments_gcal_calendar_id" value="<?php esc_attr_e( $calendar_id ); ?>">
				<?php endif; ?>
			</td>
		</tr>
		<?php
		echo ob_get_clean();
	}

	/**
	 * Generate the Manual Sync field.
	 *
	 * @param  mixed $key
	 * @param  array $data
	 *
	 * @echo string
	 */
	public function manual_sync_setting( $data ): void {
		if (isset( $_POST['wc_appointments_gcal_client_id'] )) {
            sanitize_text_field( $_POST['wc_appointments_gcal_client_id'] );
        }
		$twoway    = $_POST['wc_appointments_gcal_twoway'] ?? false;

		$get_twoway = get_option( 'wc_appointments_gcal_twoway' );

		// Two-way sync not configured yet, enable by default.
		$twoway_enabled = 'two_way' === $get_twoway;
		$twoway_enabled = $twoway ? true : $twoway_enabled;

		if ( ! $twoway_enabled ) {
			return;
		}

		ob_start();
		?>
		<tr valign="top">
			<th scope="row" class="titledesc">
				<?php echo wp_kses_post( $data['title'] ); ?>
			</th>
			<td class="forminp">
				<?php
				$last_synced = get_option( 'wc_appointments_gcal_availability_last_synced' );
				$last_synced = $last_synced ?: '';
				if ( $last_synced ) {
					$ls_timestamp = isset( $last_synced[0] ) && $last_synced[0] ? absint( $last_synced[0] ) : absint( current_time( 'timestamp' ) );
					/* translators: %1$s: date format, %2$s: time format */
					$ls_message = sprintf( __( '%1$s, %2$s', 'woocommerce-appointments' ), date_i18n( wc_appointments_date_format(), $ls_timestamp ), date_i18n( wc_appointments_time_format(), $ls_timestamp ) );
				?>
					<p class="last_synced"><?php esc_attr_e( $ls_message ); ?></p>
				<?php } else { ?>
					<p class="last_synced"><?php esc_html_e( 'No synced rules.', 'woocommerce-appointments' ); ?></p>
				<?php } ?>
				<p class="submit">
					<button type="button" class="button manual_sync"><?php esc_html_e( 'Sync Manually', 'woocommerce-appointments' ); ?></button>
				</p>
			</td>
		</tr>
		<?php
		echo ob_get_clean();
	}

	/**
	 * Render the indexing controls field.
	 */
	public function indexing_controls_setting(): void {
 		if ( ! current_user_can( 'manage_woocommerce' ) ) {
 			return;
 		}
 		wp_create_nonce( 'wc_appointments_admin_nonce' );
 		$progress   = get_option( 'wc_appointments_index_progress', [] );
 		$status     = esc_html( $progress['status'] ?? '' ) ?: __( 'Idle', 'woocommerce-appointments' );
 		$total_rules     = intval( $progress['total_rules'] ?? 0 );
 		$processed_rules = intval( $progress['processed_rules'] ?? 0 );
 		$total_appts     = intval( $progress['total_appointments'] ?? 0 );
 		$processed_appts = intval( $progress['processed_appts'] ?? 0 );

 		// Combine two progress streams (rules + appointments).
 		$total_all     = max( 1, $total_rules + $total_appts );
 		$processed_all = min( $total_all, $processed_rules + $processed_appts );
 		$percent       = max( 0, min( 100, round( ( $processed_all / $total_all ) * 100 ) ) );

		// Get last completion info
		$last_completed = get_option( 'wc_appointments_last_index_completed', [] );

 		echo '<fieldset>';
 		echo '<p>';
 		echo '<button type="button" class="button button-primary" id="wc-appointments-start-reindex">' . esc_html__( 'Re-index Now', 'woocommerce-appointments' ) . '</button> ';
		/* translators: %s: appointment status */
		echo '<span id="wc-appointments-index-status">' . sprintf( esc_html__( 'Status: %s', 'woocommerce-appointments' ), $status ) . '</span>';
        echo '</p>';

        echo '<div id="wc-appointments-index-progress">';
        echo '<div class="progress-bar" style="width:' . esc_attr( $percent ) . '%;"></div>';
        echo '<div class="progress-text"></div>';
        echo '</div>';
        echo '<p class="description" id="wc-appointments-index-counts"></p>';

		// Display last completion info
		if ( ! empty( $last_completed['timestamp'] ) ) {
			$completed_time = wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $last_completed['timestamp'] );
			$total_rules = (int) ( $last_completed['total_rules'] ?? 0 );
			$total_appointments = (int) ( $last_completed['total_appointments'] ?? 0 );
			$total_indexed = $total_rules + $total_appointments;
			$is_auto_indexed = ! empty( $last_completed['auto_indexed'] );

			echo '<p class="description wc-appointments-last-indexing">';
			if ( $is_auto_indexed ) {
				echo sprintf(
					/* translators: %1$s: date of last indexing, %2$d: number of rules, %3$d: number of appointments */
					esc_html__( 'Last indexing update: %1$s (%2$d rules, %3$d appointments) - Automatic', 'woocommerce-appointments' ),
				    '<strong>' . esc_html( $completed_time ) . '</strong>',
				    $total_rules,
				    $total_appointments,
				);
			} else {
				$cache_rows = (int) ( $last_completed['cache_rows_created'] ?? 0 );
				echo sprintf(
					/* translators: %1$s: date of last re-index, %2$d: number of rules, %3$d: number of appointments, %4$s: number of cache rows */
					esc_html__( 'Last manual re-index: %1$s (%2$d rules, %3$d appointments, %4$s cache rows)', 'woocommerce-appointments' ),
				    '<strong>' . esc_html( $completed_time ) . '</strong>',
				    $total_rules,
				    $total_appointments,
				    number_format_i18n( $cache_rows ),
				);
			}
			echo '</p>';
		} else {
			echo '<p class="description wc-appointments-last-indexing">';
			echo esc_html__( 'No previous indexing completed.', 'woocommerce-appointments' );
			echo '</p>';
		}

 		echo '</fieldset>';
	}
}

return new WC_Appointments_Admin_Settings();
