<?php
/**
 * The file contains definition of Settings class
 *
 * @category Class file
 * @package WLC\Algolia
 * @author White Label Coders
 * @license TO DO
 * @link TO DO
 */

namespace wlc_algolia;

use wlc_algolia\Helpers as helper;
use wlc_algolia\Algolia_Index_Helper;
use function wlc_algolia\Helpers\wlc_retrieve_selected_post_types_from_cpt_section;
use function wlc_algolia\Helpers\wlc_retrieve_searchable_post_type_objects;

defined( 'ABSPATH' ) || die( 'Direct file access is forbidden' );

/**
 * Settings Class.
 */
class Settings {
	/**
	 * Current settings tab.
	 *
	 * @var string
	 */
	private $current_tab = 'general';

	/**
	 * Plugin options.
	 *
	 * @var string
	 */
	private $options = array();

	/**
	 * Init Settings
	 *
	 * @return void
	 */
	public function __construct() {
		add_action( 'admin_menu', array( $this, 'create_plugin_settings_page' ) );
		add_action( 'admin_init', array( $this, 'setup_settings' ) );
		add_action( 'wlc_algolia_sections_cpt', array( $this, 'output_cpt_sections' ) );

		// Tab is used only for UI state (which tab to display), not for saving data; nonce verified on form submit.
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- tab is read-only UI state, not form data.
		if ( isset( $_GET['tab'] ) ) {
			$this->current_tab = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		$section_slug  = helper\wlc_sections_page_slug();
		$this->options = get_option( 'wlc_algolia_settings_' . $this->current_tab . $section_slug );//phpcs:ignore
	}

	/**
	 * Add settings page.
	 *
	 * @return void
	 */
	public function create_plugin_settings_page(): void {
		static $icon_data_uri = null;

		if ( null === $icon_data_uri ) {
			// phpcs:ignore
			$icon_base64 = base64_encode(
				'<svg width="510pt" height="510pt" viewBox="0 0 510 510" version="1.1" xmlns="http://www.w3.org/2000/svg">
				<g>
					<path fill="#ffffff" opacity="1.00" d=" M 501.87 0.00 L 510.00 0.00 L 510.00 8.20 C 508.85 4.16 505.92 1.13 501.87 0.00 Z" />
					<path fill="#ffffff" opacity="1.00" d=" M 501.43 510.00 C 505.63 508.67 509.36 505.26 510.00 500.75 L 510.00 510.00 L 501.43 510.00 Z" />
				</g>
				<g>
					<path fill="#a7aaad" opacity="1.00" d=" M 250.21 0.00 L 501.87 0.00 C 505.92 1.13 508.85 4.16 510.00 8.20 L 510.00 500.75 C 509.36 505.26 505.63 508.67 501.43 510.00 L 498.13 510.00 C 492.86 508.35 489.71 503.63 485.46 500.48 C 437.58 458.06 389.73 415.63 341.80 373.26 C 340.74 371.95 339.05 371.24 337.76 372.71 C 312.13 390.98 280.33 400.08 248.94 398.95 C 230.25 397.64 211.54 393.57 194.66 385.29 C 159.92 368.97 132.30 338.43 119.19 302.38 C 119.09 301.93 118.90 301.01 118.80 300.56 C 118.42 299.55 118.05 298.54 117.69 297.53 C 101.30 248.61 114.95 190.98 151.75 154.75 C 168.69 136.74 190.64 123.38 214.45 116.69 C 226.91 112.95 239.98 110.74 253.01 111.00 C 289.09 109.90 325.25 123.80 351.75 148.24 C 355.72 152.29 359.84 156.19 363.72 160.32 C 377.47 176.32 388.08 195.19 393.71 215.57 C 399.93 237.04 400.68 259.93 396.68 281.88 C 395.82 285.54 390.88 287.51 387.88 285.14 C 379.42 277.96 371.34 270.37 362.85 263.22 C 359.09 259.45 354.49 256.41 352.10 251.48 C 351.03 247.37 350.86 243.12 350.11 238.96 C 345.52 212.10 329.28 187.21 305.87 173.07 C 291.73 164.53 275.58 158.92 258.96 158.74 C 247.32 158.15 235.68 159.81 224.56 163.27 C 214.12 167.20 203.96 172.16 195.30 179.28 C 175.60 194.42 162.85 217.82 159.35 242.29 C 157.92 257.45 158.87 273.08 164.29 287.43 C 173.97 314.41 196.37 336.45 223.44 345.79 C 244.18 353.16 267.43 352.83 288.08 345.28 C 306.83 338.94 322.18 325.48 334.32 310.19 C 336.59 309.81 339.02 308.57 341.27 309.70 C 346.34 311.68 349.30 316.58 353.64 319.62 C 386.04 348.54 418.61 377.25 451.04 406.14 C 454.90 409.01 457.84 412.95 461.96 415.49 C 462.05 293.00 461.97 170.50 462.00 48.00 C 390.99 47.98 319.98 48.03 248.97 47.97 C 211.57 49.04 174.41 60.40 143.03 80.88 C 110.75 101.55 84.55 131.44 67.98 165.99 C 62.43 178.13 57.75 190.67 54.26 203.57 C 50.78 217.83 48.72 232.43 47.97 247.08 C 48.24 255.35 47.40 263.69 48.72 271.91 C 49.20 278.72 50.18 285.48 51.25 292.23 C 52.98 300.80 55.11 309.30 57.74 317.64 C 57.86 318.09 58.10 318.99 58.21 319.44 C 58.58 320.43 58.95 321.43 59.31 322.43 C 65.69 340.27 74.42 357.27 85.19 372.86 C 95.84 387.96 108.54 401.53 122.56 413.52 C 156.74 442.18 200.43 459.62 245.07 461.42 C 251.65 462.39 258.35 462.19 264.94 461.36 C 286.63 460.68 308.12 455.95 328.42 448.32 C 332.23 446.94 335.86 444.94 339.86 444.12 C 345.80 443.04 351.64 446.11 355.70 450.25 C 363.45 457.38 371.70 463.97 379.08 471.51 C 379.03 474.03 379.37 477.23 376.66 478.56 C 365.89 484.33 354.82 489.52 343.38 493.81 C 342.94 493.90 342.05 494.09 341.61 494.19 C 337.42 496.24 332.86 497.35 328.41 498.68 C 306.86 505.29 284.34 508.92 261.81 509.23 C 254.21 510.47 246.62 508.59 239.00 509.01 C 201.76 506.50 164.90 496.11 132.30 477.79 C 80.37 449.15 38.89 401.99 17.50 346.63 C 6.47 319.02 1.01 289.36 0.00 259.70 L 0.00 245.62 C 0.39 241.76 1.06 237.92 1.03 234.03 C 5.04 182.97 25.07 133.30 57.71 93.82 C 86.63 58.24 125.46 30.73 168.63 15.22 C 169.07 15.12 169.94 14.90 170.38 14.80 C 173.65 13.26 177.13 12.29 180.59 11.32 C 203.10 4.19 226.68 0.91 250.21 0.00 Z" />
				</g>
			</svg>'
			);

			$icon_data_uri = 'data:image/svg+xml;base64,' . $icon_base64;
		}
		//phpcs:disable
		// TODO: Add translation strings for below.
		//phpcs:enable
		add_menu_page(
			__( 'WLC Search Integration with Algolia — Settings', 'wlc-search-integration-with-algolia' ),
			__( 'WLC Search', 'wlc-search-integration-with-algolia' ),
			'manage_options',
			'wlc-algolia',
			array( $this, 'render_plugin_settings_page' ),
			$icon_data_uri,
		);
	}

	/**
	 * Render the settings page.
	 *
	 * @return void
	 */
	public function render_plugin_settings_page(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		$wlc_algolia_tabs            = $this->get_settings_tabs();
		$wlc_algolia_current_tab     = $this->get_settings_tab();
		$wlc_algolia_current_section = Algolia_Index_Helper::wlc_retrieve_current_section_name();

		$template_path = WLC_ALGOLIA_PLUGIN_DIR_PATH . 'includes/templates/admin/settings.php';

		include $template_path;
	}

	/**
	 * Register settings and add settings fields and sections.
	 *
	 * @return void
	 */
	public function setup_settings(): void {
		global $pagenow;

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( 'options.php' === $pagenow || ( 'admin.php' === $pagenow && 'wlc-algolia' === helper\get_array_value( $_GET, 'page' ) ) ) {
			$tab = helper\get_array_value( \wlc_algolia\WLC_Algolia::instance()->get_config( 'settings' ), $this->get_settings_tab() );

			if ( empty( $tab ) ) {
				return;
			}
			foreach ( helper\sort_array( $tab['sections'] ) as $section_name => $section ) {
				// Set section slug.
				$section_slug = helper\wlc_sections_page_slug();

				$wlc_algolia_settings = 'wlc_algolia_settings_' . sanitize_key( (string) helper\get_array_value( $section, 'tab' ) ) . $section_slug;
				// Register settings.
				register_setting(
					$wlc_algolia_settings,
					$wlc_algolia_settings,
					array(
						'sanitize_callback' => array( $this, 'sanitize_settings' ),
					)
				);
				if ( isset( $section['fields'] ) ) {
					// Add settings section.
					add_settings_section(
						$section_name,
						esc_html( helper\get_array_value( $section, 'title' ) ),
						array(
							$this,
							'render_settings_section',
						),
						$wlc_algolia_settings
					);

					foreach ( helper\sort_array( $section['fields'] ) as $field_name => $field_args ) {
						add_settings_field(
							$field_name,
							$field_args['label'],
							array(
								$this,
								'render_settings_field',
							),
							$wlc_algolia_settings,
							$section_name,
							array_merge( $field_args, array( 'name' => $field_name ) )
						);
					}
				}
			}
		}
	}

	/**
	 * Sanitize settings arrays saved via Settings API.
	 *
	 * @param mixed $input Raw input.
	 *
	 * @return mixed
	 */
	public function sanitize_settings( $input ) {
		if ( is_array( $input ) ) {
			return $this->sanitize_settings_array( $input );
		}

		return sanitize_text_field( (string) $input );
	}

	/**
	 * Recursively sanitize nested settings arrays.
	 *
	 * @param array $input Input array.
	 *
	 * @return array
	 */
	private function sanitize_settings_array( array $input ): array {
		$output = array();

		foreach ( $input as $key => $value ) {
			if ( is_array( $value ) ) {
				$output[ $key ] = $this->sanitize_settings_array( $value );
				continue;
			}

			$k = (string) $key;

			// Common numeric/toggle patterns across plugin settings.
			if ( 'max-suggestions' === $k ) {
				$output[ $key ] = (string) absint( $value );
				continue;
			}

			if ( 'pagination_limited_to' === $k ) {
				$sanitized_value = absint( $value );
				if ( 0 === $sanitized_value ) {
					$sanitized_value = 1000;
				}
				$output[ $key ] = (string) max( 1000, min( 20000, $sanitized_value ) );
				continue;
			}

			if (
				'enable' === $k
				|| 'index' === $k
				|| 'facet' === $k
				|| 'enable-algolia' === $k
				|| 'enable-autocomplete' === $k
				|| str_contains( $k, 'enable' )
				|| str_contains( $k, 'autosuggestion' )
			) {
				$output[ $key ] = (string) ( (int) ( '1' === (string) $value || 1 === $value || true === $value ) );
				continue;
			}

			if ( 'type' === $k ) {
				$output[ $key ] = sanitize_key( (string) $value );
				continue;
			}

			if ( 'selected_post_type' === $k ) {
				$output[ $key ] = sanitize_key( (string) $value );
				continue;
			}

			$output[ $key ] = sanitize_text_field( (string) $value );
		}

		return $output;
	}

	/**
	 * Renders settings field.
	 *
	 * @param array $args Field arguments.
	 */
	public function render_settings_field( array $args ) {
		if ( method_exists( $this, 'render_' . $args['type'] . '_field' ) ) {
			return call_user_func_array( array( $this, 'render_' . $args['type'] . '_field' ), array( $args ) );
		}

		$this->render_default_field( $args );
	}

	/**
	 * Render default options field
	 *
	 * @param array $args .
	 */
	public function render_default_field( $args ) {
		if ( ! isset( $args['name'] ) || ! isset( $args['type'] ) ) {
			return;
		}

		$value = '';
		if ( isset( $this->options[ $this->get_settings_tab() ] ) && is_array( $this->options[ $this->get_settings_tab() ] ) ) {
			$value = isset( $this->options[ $this->get_settings_tab() ][ $args['name'] ] ) ? $this->options[ $this->get_settings_tab() ][ $args['name'] ] : '';
		}

		$label      = isset( $args['label'] ) ? $args['label'] : '';
		$field_type = isset( $args['type'] ) ? $args['type'] : 'text';

		if ( 'pagination_limited_to' === $args['name'] ) {
			$normalized = absint( $value );
			if ( 0 === $normalized ) {
				$normalized = 1000;
			}
			$value = (string) max( 1000, min( 20000, $normalized ) );
		}
		?>
		<div class="wlc-algolia-field-group">
			<?php if ( ! empty( $label ) ) : ?>
				<label class="wlc-algolia-field-label" for="<?php echo esc_attr( $args['name'] ); ?>">
					<?php echo esc_html( $label ); ?>
				</label>
			<?php endif; ?>
			<input
					id="<?php echo esc_attr( $args['name'] ); ?>"
					type="<?php echo esc_attr( $field_type ); ?>"
					class="wlc-algolia-field-input"
					name="wlc_algolia_settings_<?php echo esc_attr( $this->get_settings_tab() ); ?>[<?php echo esc_attr( $this->get_settings_tab() ); ?>][<?php echo esc_attr( $args['name'] ); ?>]"
					value="<?php echo esc_attr( $value ); ?>"<?php echo ( isset( $args['required'] ) && $args['required'] ) ? 'required="required"' : ''; ?><?php echo isset( $args['min'] ) ? ' min="' . esc_attr( (string) $args['min'] ) . '"' : ''; ?><?php echo isset( $args['max'] ) ? ' max="' . esc_attr( (string) $args['max'] ) . '"' : ''; ?><?php echo isset( $args['step'] ) ? ' step="' . esc_attr( (string) $args['step'] ) . '"' : ''; ?>/>
			<?php if ( isset( $args['description'] ) && ! empty( $args['description'] ) ) : ?>
				<p class="wlc-algolia-field-description"><?php echo esc_html( $args['description'] ); ?></p>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Render toggle field
	 *
	 * @param array $args Field arguments.
	 */
	public function render_toggle_field( array $args ) {
		if ( ! isset( $args['name'] ) ) {
			return;
		}

		$value = '';
		if ( isset( $this->options[ $this->get_settings_tab() ] ) && is_array( $this->options[ $this->get_settings_tab() ] ) ) {
			$value = isset( $this->options[ $this->get_settings_tab() ][ $args['name'] ] ) ? $this->options[ $this->get_settings_tab() ][ $args['name'] ] : '';
		}

		$field_id   = 'wlc_algolia_toggle_' . esc_attr( $args['name'] );
		$field_name = 'wlc_algolia_settings_' . esc_attr( $this->get_settings_tab() ) . '[' . esc_attr( $this->get_settings_tab() ) . '][' . esc_attr( $args['name'] ) . ']';
		$label      = isset( $args['label'] ) ? $args['label'] : '';
		?>
		<div class="wlc-algolia-toggle-wrapper">
			<label class="wlc-algolia-toggle">
				<input
						type="hidden"
						name="<?php echo esc_attr( $field_name ); ?>"
						value="0"
				/>
				<input
						type="checkbox"
						id="<?php echo esc_attr( $field_id ); ?>"
						name="<?php echo esc_attr( $field_name ); ?>"
						value="1"
						<?php checked( $value, '1', false ); ?>
				/>
				<span class="wlc-algolia-toggle-slider"></span>
			</label>
			<?php if ( ! empty( $label ) ) : ?>
				<label class="wlc-algolia-toggle-label" for="<?php echo esc_attr( $field_id ); ?>">
					<?php echo esc_html( $label ); ?>
				</label>
			<?php endif; ?>
		</div>
		<?php
		if ( isset( $args['description'] ) && ! empty( $args['description'] ) ) {
			echo '<p class="wlc-algolia-field-description">' . esc_html( $args['description'] ) . '</p>';
		}
	}

	/**
	 * Renders CPT field.
	 *
	 * @param array $args Field arguments.
	 *
	 * @void
	 */
	public function render_post_types_field( array $args ): void {
		if ( isset( $args['description'] ) ) {
			echo '<p><small>' . esc_html( $args['description'] ) . '</small></p>';
		}

		$post_types         = wlc_retrieve_searchable_post_type_objects();
		$post_type_selected = $this->options ?? array();
		$default_index_name = get_option( 'wlc_algolia_settings_general' );
		$index_name         = 'wp_';
		if ( isset( $default_index_name['general'] ) ) {
			$index_name = $default_index_name['general']['index_name'] ?? '';
		}

		$checked = is_array( $post_type_selected ) ? map_deep( $post_type_selected, 'sanitize_text_field' ) : array();

		helper\render_settings_file(
			'post-types-index',
			array(
				'post_types'   => $post_types,
				'settings_tab' => $this->get_settings_tab(),
				'checked'      => $checked,
				'index_name'   => $index_name,
			)
		);
	}

	/**
	 * Gets current settings page tab.
	 *
	 * @return string
	 */
	protected function get_settings_tab() {
		$current_tab = null;

		// Get all tabs.
		$tabs = array_keys( helper\sort_array( \wlc_algolia\WLC_Algolia::instance()->get_config( 'settings' ) ) );

		$first_tab   = helper\get_first_array_value( $tabs );
		$current_tab = helper\get_array_value( $_GET, 'tab', $first_tab ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		// Set the default tab.
		if ( ! in_array( $current_tab, $tabs, true ) ) {
			$current_tab = $first_tab;
		}

		return $current_tab;
	}

	/**
	 * Gets settings page tabs.
	 *
	 * @return array
	 */
	protected function get_settings_tabs() {
		return array_map(
			function ( $tab ) {
				return helper\get_array_value( $tab, 'title' );
			},
			helper\sort_array( \wlc_algolia\WLC_Algolia::instance()->get_config( 'settings' ) )
		);
	}

	/**
	 * Renders settings section.
	 *
	 * @param array $args Section arguments.
	 */
	public function render_settings_section( $args ) {
		// Get current tab.
		$tab = helper\get_array_value( \wlc_algolia\WLC_Algolia::instance()->get_config( 'settings' ), $this->get_settings_tab() );

		if ( empty( $tab ) ) {
			return;
		}

		// Get current section.
		$section = helper\get_array_value( $tab['sections'], $args['id'] );

		if ( empty( $section ) ) {
			return;
		}

		// Render description.
		if ( isset( $section['description'] ) ) {
			echo '<p>' . esc_html( $section['description'] ) . '</p>';
		}
	}

	/**
	 * Render fields for indexing.
	 *
	 * @param array $args array of args.
	 *
	 * @return void
	 */
	public function render_cpt_field( array $args ): void {
		$post_type = Algolia_Index_Helper::wlc_retrieve_current_section_name();
		helper\render_settings_file(
			'schema/attributes',
			array(
				'args'        => $args,
				'tab'         => $this->get_settings_tab(),
				'options'     => $this->options,
				'index_types' => Algolia_Index_Helper::wlc_prepare_index_types(),
				'post_type'   => $post_type,
				'default'     => Algolia_Index_Helper::wlc_get_default_index_fields(),
			)
		);
	}

	/**
	 * Render Autocomplete Fields.
	 *
	 * @param array $_args Array of args (unused; required by callback signature).
	 *
	 * @return void
	 */
	public function render_autocomplete_field( array $_args ): void { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid, Generic.CodeAnalysis.UnusedFunctionParameter.Found
		$post_types         = wlc_retrieve_searchable_post_type_objects();
		$default_index_name = get_option( 'wlc_algolia_settings_general' );
		$index_name         = 'wp_';

		if ( isset( $default_index_name['general'] ) ) {
			$index_name = $default_index_name['general']['index_name'] ?? '';
		}

	    $indexes = wlc_retrieve_selected_post_types_from_cpt_section(); //phpcs:ignore

		helper\render_settings_file(
			'autocomplete',
			array(
				'post_types'         => $post_types,
				'settings_tab'       => $this->get_settings_tab(),
				'options'            => $this->options,
				'default_index_name' => $index_name, //phpcs:ignore
				'indexes'            => $indexes, //phpcs:ignore
			)
		);
	}

	/**
	 * Output Sections.
	 *
	 * @return void
	 */
	public function output_cpt_sections(): void {
		$sections = $this->get_cpt_section();

		if ( empty( $sections ) || 1 === count( $sections ) ) {
			return;
		}

		$current_section = Algolia_Index_Helper::wlc_retrieve_current_section_name();

		helper\render_settings_file(
			'cpt-sections',
			array(
				'sections'        => $sections,
				'current_section' => $current_section,
			)
		);
	}

	/**
	 * Get all sections for cpt settings tab.
	 *
	 * @return array
	 */
	public function get_cpt_section(): array {
		$post_types = wlc_retrieve_searchable_post_type_objects();
		$sections   = array();
		foreach ( $post_types as $post_type => $type ) {
			$sections[ $post_type ] = sanitize_text_field( (string) $type->labels->name );

		}

		return apply_filters( 'wlc_cpt_sections', $sections ); //phpcs:ignore
	}
}
