<?php
/**
 * AJAX Handler class for the plugin.
 * 
 * @package WPStaticHTMLPages
 */

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

class WPSH_Ajax {

	/**
	 * Initialize AJAX hooks.
	 */
	public function init() {
		$actions = array(
			'generate_all',
			'interrupt_generation',
			'clear_interrupt',
			'mark_completed',
			'refresh_nonces',
			'clear_cache',
			'update_htaccess',
			'save_redirection',
			'delete_redirection',
			'bulk_delete_redirections',
			'toggle_redirection_rule',
			'export_redirections',
			'import_redirections',
			'save_settings',
			'sync_redirections',
			'get_logs',
			'clear_logs',
			'export_logs'
		);

		foreach ( $actions as $action ) {
			add_action( "wp_ajax_wpsh_{$action}", array( $this, $action ) );
		}
	}

	/**
	 * Batch generation handler.
	 */
	public function generate_all() {
		check_ajax_referer( 'wpsh_generate_all', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		
		$phase = isset( $_POST['phase'] ) ? sanitize_text_field( wp_unslash( $_POST['phase'] ) ) : 'posts';
		$offset = isset( $_POST['offset'] ) ? intval( wp_unslash( $_POST['offset'] ) ) : 0;
		$limit = max( 1, (int) apply_filters( 'wpsh_generation_batch_limit', 3 ) );
		$processed = array();
		$total_estimate = 0;
		$core = new WPSH_Core();

		$is_interrupted = function() {
			return ( get_option( 'wpsh_interrupt_flag' ) === '1' );
		};

		if ( $phase === 'posts' && $offset === 0 ) {
			$excluded_types = (array) get_option( 'wpsh_excluded_post_types', array() );
			$public_types = get_post_types( array( 'public' => true ) );
			foreach ( $public_types as $type ) {
				if ( in_array( $type, $excluded_types, true ) ) continue;
				$total_estimate += intval( wp_count_posts( $type )->publish );
			}
			$public_tax = get_taxonomies( array( 'public' => true ), 'names' );
			foreach ( $public_tax as $tax ) {
				$total_estimate += wp_count_terms( array( 'taxonomy' => $tax ) );
			}
			$total_estimate += count( $core->get_archive_base_urls() ) + $core->get_total_archive_pagination_pages();
			$total_estimate += count( $core->get_all_cpt_listing_generation_urls() );
		}

		if ( $phase === 'posts' ) {
			if ( $offset === 0 ) {
				$special_urls = $core->get_archive_base_urls();

				// Also include mapped CPT listing pages (CPT may not have a native archive endpoint),
				// including the discovered paginated variants when available.
				$special_urls = array_merge( $special_urls, $core->get_all_cpt_listing_generation_urls() );
				
				foreach ( $special_urls as $url ) {
					if ( $is_interrupted() ) break;
					$result = $core->generate_html_by_url( $url );
					if ( true === $result ) {
						$processed[] = 'Archive Base: ' . $url;
					} elseif ( $core->maybe_queue_retryable_generation( $url, $result ) ) {
						$processed[] = 'Queued for background retry: ' . $url;
					} else {
						$processed[] = 'FAILED: ' . $url . ' - ' . $result;
					}
				}
			}
			
			if ( $is_interrupted() ) {
				 wp_send_json_success( array( 'complete' => false, 'next_phase' => 'posts', 'next_offset' => $offset, 'processed' => $processed, 'interrupted' => true ) );
				 return;
			}

			$excluded_types = (array) get_option( 'wpsh_excluded_post_types', array() );
			$public_types = get_post_types( array( 'public' => true ) );
			$eligible_types = array_diff( $public_types, $excluded_types );

			$args = array(
				'post_type'      => $eligible_types ?: 'none',
				'post_status'    => 'publish',
				'posts_per_page' => $limit,
				'offset'         => $offset,
				'fields'         => 'ids',
				'orderby'        => 'ID',
				'order'          => 'ASC'
			);
			
			$query = new WP_Query( $args );
			$posts = $query->posts;
			$processed_count = 0;

			foreach ( $posts as $post_id ) {
				if ( $is_interrupted() ) break;

				if ( WPSH_Helper::is_excluded( $post_id ) ) {
					$processed[] = 'Skipped (Excluded): ' . get_the_title( $post_id );
				} else {
					$url = get_permalink( $post_id );
					$result = $core->generate_html_by_url( $url );
					if ( true === $result ) {
						$processed[] = get_the_title( $post_id );
					} elseif ( $core->maybe_queue_retryable_generation( $url, $result ) ) {
						$processed[] = 'Queued for background retry: ' . get_the_title( $post_id );
					} else {
						$processed[] = 'FAILED ' . get_the_title( $post_id ) . ': ' . $result;
					}
				}
				$processed_count++;
			}
			
			$is_phase_complete = ( count( $posts ) < $limit ) && ( $processed_count === count( $posts ) );
			wp_send_json_success( array(
				'complete'       => false,
				'next_phase'     => $is_phase_complete ? 'archive_pagination' : 'posts',
				'next_offset'    => $is_phase_complete ? 0 : ( $offset + $processed_count ),
				'processed'      => $processed,
				'total_estimate' => $total_estimate,
				'interrupted'    => ( $processed_count < count( $posts ) )
			) );
			return;
		}
		if ( in_array( $phase, array( 'blog_pagination', 'archive_pagination' ), true ) ) {
			$pagination_items = $core->get_archive_pagination_items( $offset, $limit );

			if ( empty( $pagination_items ) ) {
				$core->cleanup_all_stale_archive_pagination();
				wp_send_json_success( array(
					'complete'    => false,
					'next_phase'  => 'terms',
					'next_offset' => 0,
					'processed'   => array( 'No paginated archive pages found.' ),
				) );
				return;
			}

			$processed_count = 0;
			foreach ( $pagination_items as $item ) {
				if ( $is_interrupted() ) break;

				$result = $core->generate_html_by_url( $item['url'] );
				$label  = ucfirst( str_replace( '_', ' ', $item['post_type'] ) ) . ' Archive Page: ' . $item['page_number'];
				if ( true === $result ) {
					$processed[] = $label;
				} elseif ( $core->maybe_queue_retryable_generation( $item['url'], $result ) ) {
					$processed[] = 'Queued for background retry: ' . $label;
				} else {
					$processed[] = 'FAILED ' . $label . ': ' . $result;
				}
				$processed_count++;
			}

			$is_phase_complete = ( count( $pagination_items ) < $limit ) && ( $processed_count === count( $pagination_items ) );
			if ( $is_phase_complete ) {
				$core->cleanup_all_stale_archive_pagination();
			}

			wp_send_json_success( array(
				'complete'    => false,
				'next_phase'  => $is_phase_complete ? 'terms' : 'archive_pagination',
				'next_offset' => $is_phase_complete ? 0 : ( $offset + $processed_count ),
				'processed'   => $processed,
				'interrupted' => ( $processed_count < count( $pagination_items ) )
			) );
			return;
		}
		if ( $phase === 'terms' ) {
			$excluded_tax = (array) get_option( 'wpsh_excluded_taxonomies', array() );
			$taxonomies = get_taxonomies( array( 'public' => true ), 'names' );
			$eligible_tax = array_diff( $taxonomies, $excluded_tax );

			if ( empty( $eligible_tax ) ) {
				 wp_send_json_success( array( 'complete' => true, 'processed' => array( 'No public taxonomies found or all excluded.' ) ) );
				 return;
			}

			$all_terms = get_terms( array(
				'taxonomy'   => $eligible_tax,
				'hide_empty' => true,
				'number'     => $limit,
				'offset'     => $offset,
				'fields'     => 'ids'
			) );
			
			if ( is_wp_error( $all_terms ) || empty( $all_terms ) ) {
				 wp_send_json_success( array( 'complete' => true, 'processed' => array( 'No remaining terms.' ) ) );
				 return;
			}
			
			$processed_count = 0;
			foreach ( $all_terms as $term_id ) {
				 if ( $is_interrupted() ) break;
				 $term = get_term( $term_id );
				 if ( $term && ! is_wp_error( $term ) ) {
					 $url = get_term_link( $term );
					 if ( ! is_wp_error( $url ) ) {
						 $result = $core->generate_html_by_url( $url );
						 if ( true === $result ) {
							 $processed[] = 'Archive: ' . $term->name;
						 } elseif ( $core->maybe_queue_retryable_generation( $url, $result ) ) {
							 $processed[] = 'Queued for background retry: Archive: ' . $term->name;
						 } else {
							 $processed[] = 'FAILED Archive: ' . $term->name . ': ' . $result;
						 }
					 }
				 }
				 $processed_count++;
			}
			
			$is_phase_complete = ( count( $all_terms ) < $limit ) && ( $processed_count === count( $all_terms ) );
			wp_send_json_success( array(
				'complete'    => $is_phase_complete,
				'next_phase'  => $is_phase_complete ? 'done' : 'terms',
				'next_offset' => $is_phase_complete ? 0 : ( $offset + $processed_count ),
				'processed'   => $processed,
				'interrupted' => ( $processed_count < count( $all_terms ) )
			) );
			return;
		}
		
		wp_send_json_error( 'Invalid Phase' );
	}

	public function interrupt_generation() {
		check_ajax_referer( 'wpsh_generate_all', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		update_option( 'wpsh_interrupt_flag', '1' );
		wp_send_json_success();
	}

	public function clear_interrupt() {
		check_ajax_referer( 'wpsh_generate_all', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		update_option( 'wpsh_interrupt_flag', '0' );
		wp_send_json_success();
	}

	public function mark_completed() {
		check_ajax_referer( 'wpsh_generate_all', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		$time = current_time( 'timestamp' );
		update_option( 'wpsh_last_generated', $time );
		$date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
		wp_send_json_success( array( 'time' => date_i18n( $date_format, $time ) ) );
	}

	/**
	 * Refresh admin nonces for long-lived admin sessions.
	 */
	public function refresh_nonces() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( 'Permission denied', 403 );
		}

		wp_send_json_success(
			array(
				'nonces' => array(
					'generate' => wp_create_nonce( 'wpsh_generate_all' ),
					'clear'    => wp_create_nonce( 'wpsh_clear_cache' ),
					'redir'    => wp_create_nonce( 'wpsh_redir_nonce' ),
					'settings' => wp_create_nonce( 'wpsh_settings_nonce' ),
					'htaccess' => wp_create_nonce( 'wpsh_update_htaccess' ),
				),
			)
		);
	}

	public function clear_cache() {
		check_ajax_referer( 'wpsh_clear_cache', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );

		global $wp_filesystem;
		if ( empty( $wp_filesystem ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
			WP_Filesystem();
		}
		
		$dir = WPSH_Helper::get_dir();
		if ( $wp_filesystem->exists( $dir ) ) {
			// Log all files before deletion
			$files = $wp_filesystem->dirlist( $dir, true, true );
			$deleted_count = 0;
			
			if ( ! empty( $files ) ) {
				foreach ( $files as $file ) {
					if ( $file['name'] === '.' || $file['name'] === '..' ) continue;
					
					$file_path = $dir . '/' . $file['name'];
					if ( $file['type'] === 'f' ) {
						// It's a file
						WPSH_Logger::deleted( 'Static file removed during cache clear', array(
							'path' => $file_path,
							'file' => $file['name'],
							'size' => isset( $file['size'] ) ? $file['size'] : 0,
							'reason' => 'cache_clear'
						) );
						$deleted_count++;
					} elseif ( $file['type'] === 'd' ) {
						// It's a directory - log directory removal
						WPSH_Logger::deleted( 'Static directory removed during cache clear', array(
							'path' => $file_path,
							'directory' => $file['name'],
							'reason' => 'cache_clear'
						) );
					}
				}
			}
			
			WPSH_Logger::info( 'Cache clear operation completed', array(
				'total_files_deleted' => $deleted_count,
				'directory' => $dir,
				'user_initiated' => true
			) );
			
			// Delete the entire directory and recreate it
			$wp_filesystem->delete( $dir, true );
			wp_mkdir_p( $dir );
		} else {
			WPSH_Logger::info( 'Cache clear attempted on non-existent directory', array(
				'directory' => $dir,
				'reason' => 'directory_not_found'
			) );
		}
		
		wp_send_json_success( 'Cache cleared' );
	}

	public function update_htaccess() {
		check_ajax_referer( 'wpsh_update_htaccess', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		if ( WPSH_Htaccess::update_rules() ) wp_send_json_success( '.htaccess updated' );
		else wp_send_json_error( 'Failed to update .htaccess' );
	}

	public function save_redirection() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		
		$source = isset( $_POST['source'] ) ? WPSH_Helper::clean_redir_source( sanitize_text_field( wp_unslash( $_POST['source'] ) ) ) : '';
		$target = isset( $_POST['target'] ) ? sanitize_text_field( wp_unslash( $_POST['target'] ) ) : '';
		if ( is_numeric( $target ) ) {
			$permalink = get_permalink( intval( $target ) );
			if ( $permalink ) {
				$target = $permalink;
			}
		}

		$code   = isset( $_POST['code'] ) ? intval( wp_unslash( $_POST['code'] ) ) : 301;
		$idx    = isset( $_POST['idx'] ) ? intval( wp_unslash( $_POST['idx'] ) ) : -1;
		
		if ( empty( $target ) ) wp_send_json_error( 'Target is required.' );
		
		$redirs = get_option( 'wpsh_redirections', array() );
		$data = array(
			'source' => $source,
			'target' => $target,
			'code'   => $code,
			'active' => '1',
			'hits'   => ( $idx >= 0 && isset( $redirs[$idx]['hits'] ) ) ? $redirs[$idx]['hits'] : 0
		);

		if ( $idx >= 0 && isset( $redirs[$idx] ) ) $redirs[$idx] = $data;
		else $redirs[] = $data;

		update_option( 'wpsh_redirections', $redirs );
		WPSH_Htaccess::update_rules();
		wp_send_json_success();
	}

	public function delete_redirection() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		$idx = isset( $_POST['idx'] ) ? intval( $_POST['idx'] ) : -1;
		$redirs = get_option( 'wpsh_redirections', array() );
		if ( isset( $redirs[$idx] ) ) {
			unset( $redirs[$idx] );
			update_option( 'wpsh_redirections', array_values( $redirs ) );
			WPSH_Htaccess::update_rules();
			wp_send_json_success();
		}
		wp_send_json_error( 'Invalid index' );
	}

	public function bulk_delete_redirections() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		$indices = isset( $_POST['indices'] ) ? array_map( 'intval', (array) wp_unslash( $_POST['indices'] ) ) : array();
		$redirs = get_option( 'wpsh_redirections', array() );
		foreach ( $indices as $idx ) {
			if ( isset( $redirs[$idx] ) ) unset( $redirs[$idx] );
		}
		update_option( 'wpsh_redirections', array_values( $redirs ) );
		WPSH_Htaccess::update_rules();
		wp_send_json_success();
	}

	public function toggle_redirection_rule() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		$idx = isset( $_POST['idx'] ) ? intval( wp_unslash( $_POST['idx'] ) ) : -1;
		$active = isset( $_POST['active'] ) ? sanitize_text_field( wp_unslash( $_POST['active'] ) ) : '1';
		$redirs = get_option( 'wpsh_redirections', array() );
		if ( isset( $redirs[$idx] ) ) {
			$redirs[$idx]['active'] = $active;
			update_option( 'wpsh_redirections', $redirs );
			WPSH_Htaccess::update_rules();
			wp_send_json_success();
		}
		wp_send_json_error();
	}

	public function export_redirections() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();
		
		$redirs = get_option( 'wpsh_redirections', array() );
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
		$output = fopen( 'php://temp', 'r+' );
		
		// Header.
		fputcsv( $output, array( 'Source', 'Target', 'Code', 'Active', 'Hits' ) );
		
		foreach ( $redirs as $r ) {
			fputcsv( $output, array(
				$r['source'],
				$r['target'],
				$r['code'],
				$r['active'],
				isset( $r['hits'] ) ? $r['hits'] : 0
			) );
		}
		
		rewind( $output );
		$csv = stream_get_contents( $output );
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
		fclose( $output );
		
		wp_send_json_success( $csv );
	}

	public function import_redirections() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();
		
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$data = isset( $_POST['csv_data'] ) ? wp_unslash( $_POST['csv_data'] ) : ''; 
		if ( empty( $data ) ) wp_send_json_error( 'No data provided.' );

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
		$output = fopen( 'php://temp', 'r+' );
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
		fwrite( $output, $data );
		rewind( $output );

		$redirs = get_option( 'wpsh_redirections', array() );
		$count = 0;
		$header_skipped = false;
		
		while ( ( $cols = fgetcsv( $output ) ) !== false ) {
			if ( ! $header_skipped ) {
				$header_skipped = true;
				continue;
			}
			
			if ( count( $cols ) >= 2 ) {
				$target = sanitize_text_field( trim( $cols[1] ) );
				if ( is_numeric( $target ) ) {
					$permalink = get_permalink( intval( $target ) );
					if ( $permalink ) {
						$target = $permalink;
					}
				}

				$redirs[] = array(
					'source' => WPSH_Helper::clean_redir_source( sanitize_text_field( $cols[0] ) ),
					'target' => $target,
					'code'   => isset( $cols[2] ) ? intval( $cols[2] ) : 301,
					'active' => ( isset( $cols[3] ) && $cols[3] === '0' ) ? '0' : '1',
					'hits'   => isset( $cols[4] ) ? intval( $cols[4] ) : 0
				);
				$count++;
			}
		}
		
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
		fclose( $output );
		update_option( 'wpsh_redirections', $redirs );
		WPSH_Htaccess::update_rules();
		wp_send_json_success( "$count rules imported." );
	}

	public function save_settings() {
		check_ajax_referer( 'wpsh_settings_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error();

		$nonce_auto_refresh_enabled = isset( $_POST['nonce_auto_refresh_enabled'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce_auto_refresh_enabled'] ) ) : '1';
		$nonce_auto_refresh_enabled = ( '1' === $nonce_auto_refresh_enabled ) ? '1' : '0';

		$allowed_intervals_ms = array(
			5 * MINUTE_IN_SECONDS * 1000,
			10 * MINUTE_IN_SECONDS * 1000,
			15 * MINUTE_IN_SECONDS * 1000,
			30 * MINUTE_IN_SECONDS * 1000,
			45 * MINUTE_IN_SECONDS * 1000,
			HOUR_IN_SECONDS * 1000,
			2 * HOUR_IN_SECONDS * 1000,
			6 * HOUR_IN_SECONDS * 1000,
		);
		$nonce_auto_refresh_interval_ms = isset( $_POST['nonce_auto_refresh_interval_ms'] ) ? intval( wp_unslash( $_POST['nonce_auto_refresh_interval_ms'] ) ) : ( 5 * MINUTE_IN_SECONDS * 1000 );
		if ( ! in_array( $nonce_auto_refresh_interval_ms, $allowed_intervals_ms, true ) ) {
			$nonce_auto_refresh_interval_ms = 5 * MINUTE_IN_SECONDS * 1000;
		}

		update_option( 'wpsh_nonce_auto_refresh_enabled', $nonce_auto_refresh_enabled );
		update_option( 'wpsh_nonce_auto_refresh_interval_ms', $nonce_auto_refresh_interval_ms );
		
		$old_excluded = (array) get_option( 'wpsh_excluded_post_types', array() );
		$excluded = isset( $_POST['excluded_post_types'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['excluded_post_types'] ) ) : array();
		update_option( 'wpsh_excluded_post_types', $excluded );

		$old_excluded_tax = (array) get_option( 'wpsh_excluded_taxonomies', array() );
		$excluded_tax = isset( $_POST['excluded_taxonomies'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['excluded_taxonomies'] ) ) : array();
		update_option( 'wpsh_excluded_taxonomies', $excluded_tax );

		// CPT listing page mapping: post_type => url/path/page_id
		$old_map = (array) get_option( 'wpsh_cpt_listing_page_map', array() );
		$new_map = array();
		$post_types = isset( $_POST['cpt_listing_page_post_types'] ) ? array_map( 'sanitize_key', (array) wp_unslash( $_POST['cpt_listing_page_post_types'] ) ) : array();
		$values     = isset( $_POST['cpt_listing_page_values'] ) ? array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['cpt_listing_page_values'] ) ) : array();

		$count = min( count( $post_types ), count( $values ) );
		for ( $i = 0; $i < $count; $i++ ) {
			$key = $post_types[ $i ];
			$val = trim( (string) $values[ $i ] );
			if ( empty( $key ) || '' === $val ) continue;
			$new_map[ $key ] = $val;
		}

		// If a CPT is excluded from static generation, remove its mapped listing page(s)
		// from settings as well (so it must be re-entered manually when re-included).
		$excluded_post_types = array_map( 'sanitize_key', (array) $excluded );
		foreach ( $excluded_post_types as $excluded_type ) {
			if ( isset( $new_map[ $excluded_type ] ) ) {
				unset( $new_map[ $excluded_type ] );
			}
		}

		update_option( 'wpsh_cpt_listing_page_map', $new_map );
		
		// If new post type exclusions were added, delete legacy static files for those types.
		$newly_excluded = array_diff( $excluded, $old_excluded );
		if ( ! empty( $newly_excluded ) ) {
			$core = new WPSH_Core();
			$posts = get_posts( array(
				'post_type'   => $newly_excluded,
				'post_status' => 'publish',
				'numberposts' => -1,
				'fields'      => 'ids'
			) );
			
			// Automatic deletion of existing static files for newly-excluded
			// post types has been disabled to avoid unintended cache loss.
		}

		// If post types were UN-excluded, we might want to suggest regeneration.
		$newly_included = array_diff( $old_excluded, $excluded );

		// If mapping changed, suggest regeneration so mapped listing pages exist/refresh.
		$map_changed = ( $old_map !== $new_map );

		WPSH_Htaccess::update_rules();
		wp_send_json_success( array(
			'needs_regeneration' => ! empty( $newly_included ) || $map_changed,
			'nonce_auto_refresh' => array(
				'enabled'     => ( '1' === $nonce_auto_refresh_enabled ),
				'interval_ms' => $nonce_auto_refresh_interval_ms,
			),
		) );
	}

	public function sync_redirections() {
		check_ajax_referer( 'wpsh_redir_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );
		if ( WPSH_Htaccess::update_rules() ) wp_send_json_success( 'Rules synced to .htaccess' );
		else wp_send_json_error( 'Sync failed' );
	}

	/**
	 * Get logs handler
	 */
	public function get_logs() {
		check_ajax_referer( 'wpsh_settings_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );

		$args = array(
			'level'     => isset( $_POST['level'] ) ? sanitize_text_field( wp_unslash( $_POST['level'] ) ) : '',
			'search'    => isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '',
			'date_from' => isset( $_POST['date_from'] ) ? sanitize_text_field( wp_unslash( $_POST['date_from'] ) ) : '',
			'date_to'   => isset( $_POST['date_to'] ) ? sanitize_text_field( wp_unslash( $_POST['date_to'] ) ) : '',
			'limit'     => isset( $_POST['limit'] ) ? intval( wp_unslash( $_POST['limit'] ) ) : 50,
			'offset'    => isset( $_POST['offset'] ) ? intval( wp_unslash( $_POST['offset'] ) ) : 0
		);

		$result = WPSH_Logger::get_logs( $args );
		$stats = WPSH_Logger::get_stats();

		// Format logs for display
		$formatted_logs = array();
		foreach ( $result['logs'] as $log ) {
			$user = $log['user_id'] ? get_userdata( $log['user_id'] )->user_login : 'System';
			
			$formatted_logs[] = array(
				'timestamp'   => $log['timestamp'],
				'level'       => WPSH_Logger::format_level( $log['level'] ),
				'message'     => esc_html( $log['message'] ),
				'function'    => isset( $log['function'] ) ? esc_html( $log['function'] ) : 'unknown',
				'file'        => isset( $log['file'] ) ? esc_html( $log['file'] ) : 'unknown',
				'line'        => isset( $log['line'] ) ? esc_html( $log['line'] ) : 'unknown',
				'user'        => esc_html( $user ),
				'ip_address'  => esc_html( $log['ip_address'] ),
				'memory'      => size_format( $log['memory_usage'] ),
				'context'     => ! empty( $log['context'] ) ? json_encode( $log['context'] ) : ''
			);
		}

		wp_send_json_success( array(
			'logs'  => $formatted_logs,
			'total' => $result['total'],
			'stats' => $stats
		) );
	}

	/**
	 * Clear logs handler
	 */
	public function clear_logs() {
		check_ajax_referer( 'wpsh_settings_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );

		if ( WPSH_Logger::clear_logs() ) {
			WPSH_Logger::info( 'Logs cleared by admin' );
			wp_send_json_success( 'Logs cleared successfully' );
		} else {
			wp_send_json_error( 'Failed to clear logs' );
		}
	}

	/**
	 * Export logs handler
	 */
	public function export_logs() {
		check_ajax_referer( 'wpsh_settings_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied' );

		$args = array(
			'level'     => isset( $_POST['level'] ) ? sanitize_text_field( wp_unslash( $_POST['level'] ) ) : '',
			'search'    => isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '',
			'date_from' => isset( $_POST['date_from'] ) ? sanitize_text_field( wp_unslash( $_POST['date_from'] ) ) : '',
			'date_to'   => isset( $_POST['date_to'] ) ? sanitize_text_field( wp_unslash( $_POST['date_to'] ) ) : ''
		);

		$csv = WPSH_Logger::export_logs( $args );
		
		$filename = 'moon-static-html-logs-' . gmdate( 'Y-m-d-H-i-s' ) . '.csv';
		
		header( 'Content-Type: text/csv' );
		header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
		header( 'Content-Length: ' . strlen( $csv ) );
		header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
		header( 'Expires: 0' );
		
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo $csv;
		exit;
	}
}
