<?php

namespace EasyCriticalCSS;

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

class Admin_Settings {
	public static function init() {
		add_filter( 'plugin_action_links_' . plugin_basename( Plugin::get_plugin_file() ), [ __CLASS__, 'add_settings_link' ] );

		add_action( 'admin_menu', [ __CLASS__, 'add_settings_page' ] );
		add_action( 'admin_init', [ __CLASS__, 'register_settings' ] );
		add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_scripts' ] );
		add_action( 'updated_option', [ __CLASS__, 'trigger_cache_clear' ] );
		add_action( 'updated_option_easy_cc_debug_mode', [ __CLASS__, 'trigger_log_deletion' ], 10, 2 );

		add_action( 'admin_footer', [ easy_cc_fs(), '_add_license_activation_dialog_box' ] );
	}

	public static function add_settings_link( $links ) {
		$settings_link = '<a href="' . admin_url( 'options-general.php?page=easy-critical-css-settings' ) . '">' . __( 'Settings', 'easy-critical-css' ) . '</a>';
		array_unshift( $links, $settings_link );
		return $links;
	}

	private static function render_failure_warnings() {
		// Only show for Auto-generation sites.
		if ( ! Helpers::can_run_auto_generation() ) {
			return;
		}

		global $wpdb;
		$table_name = Database::get_table_name();

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- This method requires a direct DB query.
		$escalated = $wpdb->get_results(
			$wpdb->prepare( // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				"SELECT url_hash, page_url, consecutive_failures, last_failure_class
				 FROM {$table_name}
				 WHERE consecutive_failures >= %d
				 LIMIT 5",
				Failure_Patterns::FAILURE_THRESHOLD
			)
		);
		// phpcs:enable

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

		?>
		<div class="notice notice-warning">
			<p>
				<strong><?php esc_html_e( 'Automatic Generation Failures Detected', 'easy-critical-css' ); ?></strong>
			</p>
			<p>
				<?php esc_html_e( 'Automatic generation has failed multiple times for one or more pages. This is usually caused by caching or security rules blocking the generator.', 'easy-critical-css' ); ?>
			</p>
			<ul style="margin: 10px 0; padding-left: 20px;">
				<?php
				foreach ( $escalated as $row ) {
					$display = ! empty( $row->page_url ) ? $row->page_url : $row->url_hash;
					if ( strlen( $display ) > 60 ) {
						$display = substr( $display, 0, 57 ) . '...';
					}
					echo '<li>' . esc_html( $display ) . ' (' . (int) $row->consecutive_failures . ' failures)</li>';
				}
				?>
			</ul>
			<p>
				<a href="<?php echo esc_url( Failure_Patterns::TROUBLESHOOTING_URL ); ?>" target="_blank">
					<?php esc_html_e( 'View troubleshooting guide →', 'easy-critical-css' ); ?>
				</a>
			</p>
		</div>
		<?php
	}

	public static function render_settings_page() {
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'Easy Critical CSS Settings', 'easy-critical-css' ); ?></h1>

			<?php
			self::render_failure_warnings();

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No need for nonce verification as we are using this for read-only purposes.
			if ( isset( $_GET['settings-reset'] ) && 'true' === $_GET['settings-reset'] ) {
				echo '<div class="notice notice-success"><p>'
				. esc_html__( 'All Easy Critical CSS settings have been reset.', 'easy-critical-css' )
				. '</p></div>';
			}

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No need for nonce verification as we are using this for read-only purposes.
			if ( isset( $_GET['styles-deleted'] ) && 'true' === $_GET['styles-deleted'] ) {
				echo '<div class="notice notice-success"><p>'
				. esc_html__( 'All Critical and Secondary CSS styles have been deleted.', 'easy-critical-css' )
				. '</p></div>';
			}
			?>

			<form method="post" action="options.php">
				<?php
				settings_fields( 'easy-critical-css' );
				do_settings_sections( 'easy-critical-css' );
				echo '<input type="hidden" id="easy_cc_cloudflare_changed" name="easy_cc_cloudflare_changed" value="" />';
				submit_button();
				?>
			</form>

			<hr>

			<h2><?php esc_html_e( 'Reset Settings', 'easy-critical-css' ); ?></h2>
			<p><?php esc_html_e( 'Click the button below to reset all settings to their default values. This action cannot be undone.', 'easy-critical-css' ); ?></p>

			<form id="ecc-reset-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
				data-confirm="<?php esc_attr_e( 'Are you sure you want to reset all Easy Critical CSS settings? This action CANNOT be undone.', 'easy-critical-css' ); ?>">
				<input type="hidden" name="action" value="easy_cc_reset">
				<?php wp_nonce_field( 'easy_cc_reset', 'easy_cc_nonce' ); ?>
				<p class="submit">
					<button id="ecc-reset" type="submit" class="button button-danger">
						<?php esc_html_e( 'Reset to Defaults', 'easy-critical-css' ); ?>
					</button>
				</p>
			</form>

			<div id="ecc-delete-section">
				<hr>
				<h2><?php esc_html_e( 'Delete Current Critical CSS', 'easy-critical-css' ); ?></h2>
				<p><?php esc_html_e( 'Click the button below to delete all associated Critical and Secondary CSS. This action will not clear any settings, but cannot be undone.', 'easy-critical-css' ); ?></p>
				<form id="ecc-delete-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
					data-confirm="<?php esc_attr_e( 'Are you sure you want to delete all stored Easy Critical CSS styles? This action CANNOT be undone.', 'easy-critical-css' ); ?>">
					<input type="hidden" name="action" value="easy_cc_delete">
					<?php wp_nonce_field( 'easy_cc_delete', 'easy_cc_nonce' ); ?>
					<p class="submit">
					<button id="ecc-delete" type="submit" class="button button-danger">
						<?php esc_html_e( 'Delete All Critical & Secondary CSS Styles', 'easy-critical-css' ); ?>
					</button>
					</p>
				</form>
			</div>


			<hr>
			<h2><?php esc_html_e( 'Uninstall Plugin & Delete All Data', 'easy-critical-css' ); ?></h2>
			<p><?php esc_html_e( 'Click the button below to completely uninstall the plugin and remove all data. This action cannot be undone.', 'easy-critical-css' ); ?></p>

			<form id="ecc-uninstall-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
				data-confirm="<?php esc_attr_e( 'Are you sure you want to uninstall and delete all Easy Critical CSS data? This action CANNOT be undone.', 'easy-critical-css' ); ?>">
				<input type="hidden" name="action" value="easy_cc_uninstall">
				<?php wp_nonce_field( 'easy_cc_uninstall', 'easy_cc_nonce' ); ?>
				<p class="submit">
					<button id="ecc-uninstall" class="button button-danger">
						<?php esc_html_e( 'Delete All Data & Uninstall', 'easy-critical-css' ); ?>
					</button>
				</p>
			</form>
		</div>
		<?php
	}

	public static function add_settings_page() {
		add_submenu_page(
			'options-general.php',
			__( 'Easy Critical CSS Settings', 'easy-critical-css' ),
			__( 'Easy Critical CSS', 'easy-critical-css' ),
			'manage_options',
			'easy-critical-css-settings',
			[ __CLASS__, 'render_settings_page' ]
		);
	}

	public static function render_setting_field(
		$key,
		$type = 'text',
		$options = [],
		$desc = '',
		$default_value = '',
		$default_label = '',
		$warning = ''
	) {
		$value           = get_option( "easy_cc_$key", $default_value );
		$disabled        = false;
		$masked_value    = '';
		$show_change_btn = false;
		// Cloudflare masking logic
		if ( in_array( $key, [ 'cloudflare_email', 'cloudflare_api_key', 'cloudflare_zone_id' ], true ) ) {
			$const_map = [
				'cloudflare_email'   => 'CLOUDFLARE_EMAIL',
				'cloudflare_api_key' => 'CLOUDFLARE_API_KEY',
				'cloudflare_zone_id' => 'CLOUDFLARE_ZONE_ID',
			];
			$const     = $const_map[ $key ];
			if ( defined( $const ) && constant( $const ) ) {
				$disabled = true;
				$raw      = (string) constant( $const );
				$len      = strlen( $raw );
				if ( $len > 4 ) {
					$masked_value = substr( $raw, 0, 2 ) . str_repeat( '*', $len - 4 ) . substr( $raw, -2 );
				} else {
					$masked_value = str_repeat( '*', $len );
				}
			} elseif ( ! empty( $value ) ) {
				$disabled        = true;
				$show_change_btn = true;
				$raw             = (string) $value;
				$len             = strlen( $raw );
				if ( $len > 4 ) {
					$masked_value = substr( $raw, 0, 2 ) . str_repeat( '*', $len - 4 ) . substr( $raw, -2 );
				} else {
					$masked_value = str_repeat( '*', $len );
				}
			}
		}
		?>
		<div id="<?php echo esc_attr( str_replace( '_', '-', $key ) ); ?>-container">
			
			<?php
			if ( $type === 'checkbox' ) {
				?>
				<label>
					<input type="checkbox" name="easy_cc_<?php echo esc_attr( $key ); ?>" value="1" <?php checked( $value, 1 ); ?> />
				<?php echo esc_html( ! empty( $options['label'] ) ? $options['label'] : '' ); ?>
				</label>
				<?php
			} elseif ( $type === 'checkbox-list' && ! empty( $options ) ) {
				$selected_values = is_array( $value ) ? array_keys( $value ) : [];
				$index           = 0;
				$total           = count( $options );
				foreach ( $options as $option_value => $label ) {
					?>
					<label>
						<input type="checkbox" name="easy_cc_<?php echo esc_attr( $key ); ?>[]" value="<?php echo esc_attr( $option_value ); ?>" <?php checked( in_array( $option_value, $selected_values, true ) ); ?> />
						<?php echo esc_html( ! empty( $label ) ? $label : '' ); ?>
					</label>
					<?php
					if ( ++$index < $total ) {
						echo '<br>';
					}
				}
			} elseif ( $type === 'radio' && ! empty( $options ) ) {
				$index = 0;
				$total = count( $options );
				foreach ( $options as $option_value => $label ) {
					?>
					<label>
						<input type="radio" name="easy_cc_<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $option_value ); ?>" <?php checked( $value, $option_value ); ?> />
					<?php echo esc_html( $label ); ?>
					</label>
					<?php
					if ( ++$index < $total ) {
						echo '<br>';
					}
				}
			} elseif ( $type === 'textarea' ) {
				?>
				<textarea name="easy_cc_<?php echo esc_attr( $key ); ?>" rows="5" cols="50"><?php echo esc_textarea( $value ); ?></textarea>
				<?php
			} elseif ( $type === 'text' ) {
				?>
				<input type="text" name="easy_cc_<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $disabled ? $masked_value : $value ); ?>" <?php disabled( $disabled ); ?> autocomplete="off" data-cloudflare-key="<?php echo esc_attr( $key ); ?>"
				<?php
				if ( $disabled ) {
					echo ' data-original-masked="' . esc_attr( $masked_value ) . '"';}
				?>
				/>
				<?php if ( $disabled && $show_change_btn ) { ?>
					<button type="button" class="button button-secondary ecc-cloudflare-change" data-cloudflare-key="<?php echo esc_attr( $key ); ?>"><?php esc_html_e( 'Change', 'easy-critical-css' ); ?></button>
					<button type="button" class="button button-secondary ecc-cloudflare-undo" data-cloudflare-key="<?php echo esc_attr( $key ); ?>" style="display:none; margin-left:4px;">Undo</button>
				<?php } elseif ( $disabled ) { ?>
					<span style="color:#888; font-size:12px; margin-left:8px;">(<?php esc_html_e( 'Set via constant', 'easy-critical-css' ); ?>)</span>
				<?php } ?>
				<?php
			} elseif ( $type === 'status-indicator' ) {
				$status = Helpers::get_auto_mode_status();
				$all_ok = $status['all_ok'];

				$status_color = $all_ok ? '#1e7e34' : '#b12331';
				$status_icon  = $all_ok ? '&#x2713;' : '&#x2717;';
				$status_text  = $all_ok ? __( 'Auto mode ready', 'easy-critical-css' ) : __( 'Auto mode cannot run', 'easy-critical-css' );
				$status_class = $all_ok ? 'ecc-status-ready' : 'ecc-status-blocked';
				?>
				<div class="ecc-auto-mode-status <?php echo esc_attr( $status_class ); ?>">
					<div class="ecc-status-main">
						<span class="ecc-status-icon" style="color: <?php echo esc_attr( $status_color ); ?>;">
							<?php echo esc_html( $status_icon ); ?>
						</span>
						<span class="ecc-status-text">
							<?php echo esc_html( $status_text ); ?>
						</span>
					</div>
					<div class="ecc-status-details" style="display: none;">
						<ul>
							<li>
								<strong><?php esc_html_e( 'Active API Key:', 'easy-critical-css' ); ?></strong>
								<span class="ecc-check <?php echo $status['active_key'] ? 'ecc-check-ok' : 'ecc-check-fail'; ?>">
									<?php echo $status['active_key'] ? '✓' : '✕'; ?>
								</span>
								<?php
								if ( ! $status['active_key'] ) {
									esc_html_e( 'No active API key', 'easy-critical-css' );
								}
								?>
							</li>

							<li>
								<strong><?php esc_html_e( 'Site is Public:', 'easy-critical-css' ); ?></strong>
								<span class="ecc-check <?php echo $status['local_ok'] ? 'ecc-check-ok' : 'ecc-check-fail'; ?>">
									<?php echo $status['local_ok'] ? '✓' : '✕'; ?>
								</span>
								<?php
								if ( ! $status['local_ok'] ) {
									esc_html_e( 'Site is local', 'easy-critical-css' );
								}
								?>
							</li>
							<li>
								<strong><?php esc_html_e( 'REST API Reachable:', 'easy-critical-css' ); ?></strong>
								<span class="ecc-check <?php echo $status['rest_api_ok'] ? 'ecc-check-ok' : 'ecc-check-fail'; ?>">
									<?php echo $status['rest_api_ok'] ? '✓' : '✕'; ?>
								</span>
								<?php
								if ( ! $status['rest_api_ok'] ) {
									esc_html_e( 'Generator cannot reach the site', 'easy-critical-css' );
								}
								?>
							</li>
						</ul>
					</div>
					<div style="margin-top: 10px;">
						<button type="button" class="ecc-status-toggle" style="background: none; border: none; padding: 0; color: #007cba; cursor: pointer; text-decoration: underline; font-size: 12px; margin-right: 15px;">
							<?php esc_html_e( 'Details', 'easy-critical-css' ); ?>
						</button>
						<button type="button" class="ecc-status-refresh" style="background: none; border: none; padding: 0; color: #007cba; cursor: pointer; text-decoration: underline; font-size: 12px;">
							<?php esc_html_e( 'Refresh', 'easy-critical-css' ); ?>
						</button>
					</div>
				</div>
				<?php
			}

			if ( ! empty( $desc ) ) {
				?>
				<p class="description">
					<?php
					echo wp_kses_post( $desc );
					if ( ! empty( $default_label ) ) {
						?>
						<br>
						<em>
							<?php
							echo wp_kses(
								// translators: %1$s and %3$s are opening and closing <strong> tags for emphasis. %2$s is the default value.
								sprintf( __( 'Default: %1$s%2$s%3$s.', 'easy-critical-css' ), '<strong>', esc_html( $default_label ), '</strong>' ),
								[ 'strong' => [] ]
							);
							?>
						</em>
						<?php
					}
					?>
				</p>
				<?php
			}

			if ( ! empty( $warning ) ) {
				?>
				<p style="color: #b12331; font-weight: bold;">
					<?php echo wp_kses_post( $warning ); ?>
				</p>
				<?php
			}
			?>

		</div>
		<?php
	}

	public static function get_critical_css_mode_text() {
		$getting_started_link = sprintf(
			'<p style="margin:1.5em 0;"><a href="%s" target="_blank" rel="noopener noreferrer">%s</a></p>',
			'https://criticalcss.net/docs/?utm_source=easy-critical-css-plugin&utm_medium=admin-documentation&utm_campaign=v' . Plugin::get_plugin_version(),
			esc_html__( 'Need help getting started? View the Easy Critical CSS guides.', 'easy-critical-css' )
		);

		$critical_css_mode_text = sprintf(
			// translators: %s is a link to the API site.
			__( 'Auto mode sends page data to an external API at %s and requires an API key.', 'easy-critical-css' ),
			'<a href="https://criticalcss.net/?utm_source=easy-critical-css-plugin&utm_medium=admin-main&utm_campaign=v' . Plugin::get_plugin_version() . '" target="_blank" rel="noopener noreferrer">CriticalCSS.net</a>'
		);

		// Base warning (shown in red).
		$critical_css_mode_warn  = $getting_started_link;
		$critical_css_mode_warn .= sprintf(
			'<p style="color:#b12331;font-weight:bold;">%s</p>',
			$critical_css_mode_text
		);

		if ( empty( Helpers::get_api_key() ) ) {
			// Auto mode path.
			$critical_css_mode_warn .= sprintf(
				'<p style="font-weight:bold;">%1$s <a href="%2$s">%3$s</a> · <span class="activate-license easy-critical-css"><a href="#">%4$s</a></span></p>',
				esc_html__( 'To use Auto mode, you need an API key.', 'easy-critical-css' ),
				esc_url( admin_url( 'admin.php?page=easy-critical-css-settings-pricing' ) ),
				esc_html__( 'Get an API key', 'easy-critical-css' ),
				esc_html__( 'Add your API key', 'easy-critical-css' )
			);

			// Free/manual path.
			$critical_css_mode_warn .= sprintf(
				'<p>%1$s <a href="https://criticalcss.net/?utm_source=easy-critical-css-plugin&utm_medium=free-generator&utm_campaign=v' . Plugin::get_plugin_version() . '#free-generator" target="_blank" rel="noopener noreferrer">%2$s</a> %3$s</p>',
				esc_html__( 'Staying in free Manual mode? You can generate CSS manually at', 'easy-critical-css' ),
				'CriticalCSS.net',
				esc_html__( 'and paste it into your settings.', 'easy-critical-css' )
			);
		}

		return $critical_css_mode_warn;
	}

	public static function get_exclude_css_strings() {
		$label_auto   = __( 'Exclude CSS Files from Critical CSS', 'easy-critical-css' );
		$label_manual = __( 'Always Loaded CSS Files', 'easy-critical-css' );

		$desc_auto   = __( 'Enter the CSS file URLs or partial matches that should be excluded from Critical CSS generation.', 'easy-critical-css' );
		$desc_manual = __( 'Enter the CSS file URLs or partial matches that should always be loaded (not inlined) when using Manual mode.', 'easy-critical-css' );

		$common = '<br><em>' . sprintf(
			// translators: %1$s and %2$s are opening and closing <strong> tags for emphasis.
			__( 'One entry per line. Example: %1$shttps://example.com/style.css%2$s or %1$smy-style.css%2$s', 'easy-critical-css' ),
			'<strong>',
			'</strong>'
		) . '</em>';

		return [
			'label_auto'   => $label_auto,
			'label_manual' => $label_manual,
			'desc_auto'    => $desc_auto . $common,
			'desc_manual'  => $desc_manual . $common,
		];
	}

	public static function get_settings_schema() {
		$critical_css_mode_warn = self::get_critical_css_mode_text();

		$forced_selectors_desc = '<br><em>' . sprintf(
			// translators: %1$s and %2$s are opening and closing <strong> tags for emphasis.
			__( 'One selector per line. Example: %1$s.my-class%2$s or %1$s#my-id span%2$s', 'easy-critical-css' ),
			'<strong>',
			'</strong>'
		) . '<br>' . sprintf(
			// translators: %1$s and %2$s are opening and closing <strong> tags for emphasis.
			__( 'You can use regex patterns by placing them between slashes. Example: %1$s/\\.my-plugin-id-\\d+/%2$s (matches .my-plugin-id-1, .my-plugin-id-42, etc.)', 'easy-critical-css' ),
			'<strong>',
			'</strong>'
		) . '</em>';

		$exclude_strings = self::get_exclude_css_strings();

		$settings = [
			'critical_css_mode'          => [
				'label'         => __( 'Critical CSS Mode', 'easy-critical-css' ),
				'type'          => 'radio',
				'value_type'    => 'string',
				'options'       => [
					'auto'   => __( 'Auto (Requires API)', 'easy-critical-css' ),
					'manual' => __( 'Manual', 'easy-critical-css' ),
				],
				'desc'          => __( 'Choose how Critical CSS is generated. "Auto" mode uses an external API, while "Manual" mode requires you to provide your own Critical CSS.', 'easy-critical-css' ),
				'default_value' => 'manual',
				'default_label' => 'Manual',
				'warning'       => $critical_css_mode_warn,
				'basic'         => true,
			],
			'auto_mode_status'           => [
				'label'      => '',
				'type'       => 'status-indicator',
				'value_type' => 'string',
				'desc'       => '',
				'basic'      => true,
				'hidden'     => true, // Don't register as a real setting
			],
			'secondary_css_behavior'     => [
				'label'         => __( 'Secondary CSS Behavior', 'easy-critical-css' ),
				'type'          => 'radio',
				'value_type'    => 'string',
				'options'       => [
					'secondary' => __( 'Strip unused CSS rules', 'easy-critical-css' ),
					'remaining' => __( 'Keep all remaining CSS rules', 'easy-critical-css' ),
				],
				'desc'          => __( 'This setting applies only when Critical CSS is generated through the API. After extracting Critical CSS, it determines how the remaining CSS is handled. Choose to keep all remaining CSS or strip unused rules from it.', 'easy-critical-css' ),
				'default_value' => 'secondary',
				'default_label' => 'Strip unused CSS rules',
				'warning'       => __( 'Performance Tip: Stripping unused CSS rules generally results in the biggest performance gains and lower page load times.', 'easy-critical-css' ),
				'basic'         => true,
			],
			'forced_critical_selectors'  => [
				'label'      => __( 'Forced Critical CSS Selectors', 'easy-critical-css' ),
				'type'       => 'textarea',
				'value_type' => 'array',
				'desc'       => __( 'Specify CSS selectors that should always be included in Critical CSS, even if they are not automatically detected.', 'easy-critical-css' ) . $forced_selectors_desc,
			],
			'forced_secondary_selectors' => [
				'label'      => __( 'Forced Secondary CSS Selectors', 'easy-critical-css' ),
				'type'       => 'textarea',
				'value_type' => 'array',
				'desc'       => __( 'Specify CSS selectors that should always be included in stripped Secondary CSS, even if they are normally stripped.', 'easy-critical-css' ) . $forced_selectors_desc,
			],
			'add_common_secondary'       => [
				'label'         => __( 'Include Common Secondary Selectors', 'easy-critical-css' ),
				'type'          => 'checkbox',
				'value_type'    => 'boolean',
				'options'       => [
					'label' => __( 'Include selectors commonly added via JavaScript.', 'easy-critical-css' ),
				],
				'desc'          => __( 'By default, the Critical CSS generator only captures selectors present on initial page load. Selectors that are added later by user interaction may be missed. Checking this will include a set of those common secondary selectors, and more may be added in future releases.', 'easy-critical-css' ),
				'default_value' => true,
				'default_label' => __( 'Checked', 'easy-critical-css' ),
			],
			'default_critical_css'       => [
				'label'      => __( 'Default Critical CSS', 'easy-critical-css' ),
				'type'       => 'textarea',
				'value_type' => 'string',
				'desc'       => __( 'This Critical CSS will be used as the default across all pages. If no page-specific Critical CSS exists, this will be applied.', 'easy-critical-css' ),
				'basic'      => true,
			],
			'exclude_css_files'          => [
				'label'      => $exclude_strings['label_auto'],
				'type'       => 'textarea',
				'value_type' => 'array',
				'desc'       => $exclude_strings['desc_auto'],
			],
			'ignore_cross_domain_css'    => [
				'label'         => __( 'Ignore Cross-Domain CSS', 'easy-critical-css' ),
				'type'          => 'checkbox',
				'value_type'    => 'boolean',
				'options'       => [
					'label' => __( 'Ignore stylesheets loaded from external domains when generating Critical CSS.', 'easy-critical-css' ),
				],
				'desc'          => __( 'By default, external stylesheets (hosted on other domains) are ignored during Critical CSS generation. This prevents third-party and CDN-hosted styles from being inlined into Critical CSS. Uncheck this option only if you explicitly need stylesheets from external domains to be included during generation.', 'easy-critical-css' ),
				'default_value' => 1,
				'default_label' => __( 'Checked', 'easy-critical-css' ),
				'warning'       => __( 'Warning: Unchecking this can break ad layouts, third-party scripts, or styles that load dynamically. Unchecking this setting is strongly discouraged on monetized sites unless you fully understand the impact.', 'easy-critical-css' ),

			],
			'serve_css_from_files'       => [
				'label'         => __( 'Serve Critical CSS from Files', 'easy-critical-css' ),
				'type'          => 'checkbox',
				'value_type'    => 'boolean',
				'options'       => [
					'label' => __( 'Serve Critical CSS from static files instead of the database.', 'easy-critical-css' ),
				],
				'desc'          => __( 'By default, Critical CSS is stored and served as static files. Checking this stores and saves it in the database.', 'easy-critical-css' ),
				'default_value' => true,
				'default_label' => __( 'Checked', 'easy-critical-css' ),
			],
			'regenerate_triggers'        => [
				'label'         => __( 'Regenerate Critical CSS When:', 'easy-critical-css' ),
				'type'          => 'checkbox-list',
				'value_type'    => 'array',
				'options'       => [
					'post_updated'      => __( 'A post is updated', 'easy-critical-css' ),
					'archive_updated'   => __( 'An archive is updated', 'easy-critical-css' ),
					'plugin_change'     => __( 'A plugin is activated or deactivated (Updates all Critical CSS)', 'easy-critical-css' ),
					'theme_change'      => __( 'A new theme is activated (Updates all Critical CSS)', 'easy-critical-css' ),
					'upgrader_complete' => __( 'WordPress Core, a plugin, or a theme is updated (Updates all Critical CSS)', 'easy-critical-css' ),
				],
				'desc'          => __( 'Select the actions that should automatically regenerate Critical CSS.', 'easy-critical-css' ),
				'default_value' => [
					'post_updated'      => 1,
					'archive_updated'   => 1,
					'plugin_change'     => 1,
					'theme_change'      => 1,
					'upgrader_complete' => 1,
				],
				'default_label' => __( 'All boxes checked', 'easy-critical-css' ),
			],
			'expired_css_behavior'       => [
				'label'         => __( 'Expired Critical CSS Behavior', 'easy-critical-css' ),
				'type'          => 'radio',
				'value_type'    => 'string',
				'options'       => [
					'use_expired'         => __( 'Continue using the last generated Critical CSS until a new version is ready.', 'easy-critical-css' ),
					'use_fallback'        => __( 'Temporarily fall back to default CSS until new Critical CSS is ready.', 'easy-critical-css' ),
					'deactivate_critical' => __( 'Pause Critical CSS until new Critical CSS is generated.', 'easy-critical-css' ),
				],
				'desc'          => __( 'Choose how your site should behave when Critical CSS expires but has not yet been regenerated.', 'easy-critical-css' ),
				'default_value' => 'use_expired',
				'default_label' => 'Continue using the last generated Critical CSS',
				'basic'         => true,
			],
			'cloudflare_email'           => [
				'label'      => __( 'Cloudflare Email', 'easy-critical-css' ),
				'type'       => 'text',
				'value_type' => 'string',
				'desc'       => __( 'Cloudflare account email for API access. If the CLOUDFLARE_EMAIL constant is defined, this field is disabled and the value is hidden for privacy.', 'easy-critical-css' ) . '<br><strong><a href="https://criticalcss.net/docs/cloudflare-setup/?utm_source=easy-critical-css-plugin&utm_medium=admin-setup-guide&utm_campaign=v' . Plugin::get_plugin_version() . '" target="_blank" rel="noopener noreferrer">' . __( 'View Cloudflare Setup Guide', 'easy-critical-css' ) . '</a></strong>',
			],
			'cloudflare_api_key'         => [
				'label'      => __( 'Cloudflare API Key', 'easy-critical-css' ),
				'type'       => 'text',
				'value_type' => 'string',
				'desc'       => __( 'Cloudflare API key for API access. If the CLOUDFLARE_API_KEY constant is defined, this field is disabled and the value is hidden for privacy.', 'easy-critical-css' ),
			],
			'cloudflare_zone_id'         => [
				'label'      => __( 'Cloudflare Zone ID', 'easy-critical-css' ),
				'type'       => 'text',
				'value_type' => 'string',
				'desc'       => __( 'Cloudflare Zone ID for API access. If the CLOUDFLARE_ZONE_ID constant is defined, this field is disabled and the value is hidden for privacy.', 'easy-critical-css' ),
			],
			'debug_mode'                 => [
				'label'         => __( 'Debug Mode', 'easy-critical-css' ),
				'type'          => 'checkbox',
				'value_type'    => 'boolean',
				'options'       => [
					'label' => __( 'Enable Debug for Support.', 'easy-critical-css' ),
				],
				'desc'          => __( 'This creates an Easy Critical CSS specific debug log and opens REST endpoints for support to receive it. Support must have an account on your site to be able to access this information.', 'easy-critical-css' ),
				'default_value' => false,
				'default_label' => __( 'Unchecked', 'easy-critical-css' ),
			],
		];

		return $settings;
	}

	public static function sanitize_settings( $value ) {
		$key = current_filter(); // Get current setting being sanitized.
		$key = str_replace( 'sanitize_option_easy_cc_', '', $key ); // Determine actual key.

		// Only update Cloudflare if value marked for change or previously empty.
		$cloudflare_keys = [ 'cloudflare_email', 'cloudflare_api_key', 'cloudflare_zone_id' ];
		if ( in_array( $key, $cloudflare_keys, true ) ) {
			$changed = [];
			if ( isset( $_POST['easy_cc_cloudflare_changed'] ) ) {
				// Only allow known Cloudflare keys for safety reasons.
				// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce checked below.
				$cloudflare_changed_post = '';
				if ( isset( $_POST['easy_cc_cloudflare_changed'] ) ) {
					$cloudflare_changed_post = sanitize_text_field( wp_unslash( $_POST['easy_cc_cloudflare_changed'] ) );
				}
				$raw = explode( ',', $cloudflare_changed_post );
				foreach ( $raw as $item ) {
					$item = trim( $item );
					if ( in_array( $item, $cloudflare_keys, true ) ) {
						$changed[] = $item;
					}
				}
			}
			$existing = get_option( 'easy_cc_' . $key, '' );
			if ( ! in_array( $key, $changed, true ) && $existing !== '' ) {
				// Not changed and already set, preserve existing value
				return $existing;
			}
		}

		// Nonce verification for Cloudflare settings change.
		if ( in_array( $key, $cloudflare_keys, true ) && isset( $_POST['easy_cc_cloudflare_changed'] ) ) {
			// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce checked here.
			if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'easy-critical-css-options' ) ) {
				// Nonce missing or invalid, do not process.
				return get_option( 'easy_cc_' . $key, '' );
			}
		}

		// Checkboxes.
		if ( is_bool( $value ) || $value === '1' || $value === '0' ) {
			return rest_sanitize_boolean( $value ) ? '1' : '0';
		}

		// Radio options.
		$valid_modes = [ 'auto', 'manual' ];
		if ( $key === 'critical_css_mode' && in_array( $value, $valid_modes, true ) ) {
			return $value;
		}

		$valid_behaviors = [ 'secondary', 'remaining' ];
		if ( $key === 'secondary_css_behavior' && in_array( $value, $valid_behaviors, true ) ) {
			return $value;
		}

		// URLs.
		if ( filter_var( $value, FILTER_VALIDATE_URL ) !== false ) {
			return esc_url_raw( $value );
		}

		// Excluded CSS files (List of URLs).
		if ( $key === 'exclude_css_files' && strpos( $value, "\n" ) !== false ) {
			return implode( "\n", array_map( 'esc_url_raw', explode( "\n", $value ) ) );
		}

		// CSS selectors (Textareas, both single-line and multi-line)
		if ( in_array( $key, [ 'forced_critical_selectors', 'forced_secondary_selectors' ], true ) ) {
			return trim( wp_kses_post( $value ) ); // CSS may require > so we need KSES.
		}

		// Regenerate triggers.
		if ( $key === 'regenerate_triggers' && is_array( $value ) ) {
			return array_map( fn() => '1', array_flip( $value ) );
		}

		// JSON data (future proof for potential settings import).
		if ( is_string( $value ) && Helpers::is_valid_json( $value ) ) {
			return json_decode( $value, true );
		}

		// Multi-line textareas.
		if ( is_string( $value ) && strpos( $value, "\n" ) !== false ) {
			return sanitize_textarea_field( $value );
		}

		// Default: Text field.
		return is_string( $value ) ? sanitize_text_field( $value ) : '';
	}

	public static function register_settings() {
		add_settings_section(
			'easy-critical-css-basic-section',
			__( 'Basic Settings', 'easy-critical-css' ),
			null,
			'easy-critical-css'
		);

		// Advanced settings section
		add_settings_section(
			'easy-critical-css-advanced-section',
			'',
			function () {
				?>
				<div id="ecc-advanced-settings-toggle">
					<button type="button" class="button button-secondary" id="ecc-toggle-advanced">
						<span class="dashicons dashicons-arrow-right"></span>
						<?php esc_html_e( 'Show Advanced Settings', 'easy-critical-css' ); ?>
					</button>
				</div>
				<div id="ecc-advanced-settings" style="display: none;">
					<h3><?php esc_html_e( 'Advanced Settings', 'easy-critical-css' ); ?></h3>
					<p class="description"><?php esc_html_e( 'These settings provide fine-grained control over Critical CSS generation and behavior. Most users can safely leave these at their default values.', 'easy-critical-css' ); ?></p>
					<table class="form-table" role="presentation">
				<?php
			},
			'easy-critical-css'
		);

		$settings = self::get_settings_schema();
		foreach ( $settings as $key => $setting ) {
			$is_basic  = isset( $setting['basic'] ) && $setting['basic'];
			$is_hidden = isset( $setting['hidden'] ) && $setting['hidden'];
			$section   = $is_basic ? 'easy-critical-css-basic-section' : 'easy-critical-css-advanced-section';

			add_settings_field(
				"easy_cc_$key",
				$setting['label'],
				function () use ( $key, $setting, $is_basic, $is_hidden ) {
					static $last_advanced_key = null;
					static $all_keys          = null;

					if ( $all_keys === null ) {
						$all_keys = array_keys( self::get_settings_schema() );
						// Find the last advanced setting
						foreach ( array_reverse( $all_keys ) as $check_key ) {
							$check_setting = self::get_settings_schema()[ $check_key ];
							if ( ! isset( $check_setting['basic'] ) || ! $check_setting['basic'] ) {
								$last_advanced_key = $check_key;
								break;
							}
						}
					}

					$wrapper_class = $is_basic ? 'ecc-basic-setting' : 'ecc-advanced-setting';
					echo '<div class="' . esc_attr( $wrapper_class ) . '">';
					self::render_setting_field(
						$key,
						$setting['type'] ?? '',
						$setting['options'] ?? [],
						$setting['desc'] ?? '',
						$setting['default_value'] ?? '',
						$setting['default_label'] ?? '',
						$setting['warning'] ?? ''
					);
					echo '</div>';

					// Close advanced settings div after the last advanced setting
					if ( $key === $last_advanced_key ) {
						echo '</table></div><!-- #ecc-advanced-settings -->';
					}
				},
				'easy-critical-css',
				$section
			);

			// Skip registering the setting if it's hidden (like auto_mode_status).
			if ( $is_hidden ) {
				continue;
			}

			// Plugin Checker warns against dynamic arguments in the third param. Sanitization has been double-checked.
			register_setting( // phpcs:ignore PluginCheck.CodeAnalysis.SettingSanitization.register_settingDynamic
				'easy-critical-css',
				"easy_cc_$key",
				[
					'type'              => $setting['value_type'],
					'sanitize_callback' => [ __CLASS__, 'sanitize_settings' ],
				]
			);
		}
	}

	public static function enqueue_scripts( $hook ) {
		if ( $hook !== 'settings_page_easy-critical-css-settings' ) {
			return;
		}

		wp_enqueue_script(
			'easy-critical-css-admin',
			plugins_url( 'assets/admin.js', Plugin::get_plugin_file() ),
			[],
			Plugin::get_plugin_version(),
			true
		);

		$exclude_strings = self::get_exclude_css_strings();
		wp_localize_script(
			'easy-critical-css-admin',
			'easyCriticalCss',
			[
				'restUrl'            => esc_url_raw( rest_url( 'easy-critical-css/v1/' ) ),
				'nonce'              => wp_create_nonce( 'wp_rest' ),
				'excludeLabelAuto'   => $exclude_strings['label_auto'],
				'excludeLabelManual' => $exclude_strings['label_manual'],
				'excludeDescAuto'    => $exclude_strings['desc_auto'],
				'excludeDescManual'  => $exclude_strings['desc_manual'],
			]
		);

		wp_enqueue_style(
			'easy-critical-css-admin',
			plugins_url( 'assets/admin.css', Plugin::get_plugin_file() ),
			null,
			Plugin::get_plugin_version()
		);
	}

	public static function trigger_cache_clear( $option_name ) {
		// What settings should trigger a cache clear
		$critical_css_settings = [
			'easy_cc_forced_critical_selectors',
			'easy_cc_forced_secondary_selectors',
			'easy_cc_default_critical_css',
			'easy_cc_exclude_css_files',
			'easy_cc_expired_css_behavior',
			'easy_cc_serve_css_from_files',
		];

		// If we have one of our critical settings, expire all CSS.
		if ( in_array( $option_name, $critical_css_settings, true ) ) {
			Critical_CSS::expire_all_css();

			// Clear cached transients related to site environment checks.
			Timed_Option::delete_all();
		}
	}

	public static function trigger_log_deletion( $old_value, $new_value ) {
		// If mode is inactive, delete the file.
		if ( ! $new_value ) {
			Debug::clear_log();
		}
	}
}
