<?php
/**
 * Settings page class.
 *
 * @package BW_Admin_Column
 */

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

class BW_Admin_Column_Settings {

	/**
	 * Singleton instance.
	 *
	 * @var BW_Admin_Column_Settings|null
	 */
	private static $instance = null;

	/**
	 * Option name in wp_options.
	 *
	 * @var string
	 */
	private $option_name = 'bw_admin_column_settings';

	/**
	 * Get singleton instance.
	 *
	 * @return BW_Admin_Column_Settings
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor.
	 */
	private function __construct() {
		add_action( 'admin_menu', array( $this, 'bw_add_settings_page' ) );
		add_action( 'admin_init', array( $this, 'bw_register_settings' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'bw_enqueue_settings_assets' ) );
	}

	/**
	 * Register the settings page under Settings menu.
	 */
	public function bw_add_settings_page() {
		add_options_page(
			__( 'Admin Column Configuration', 'bw-admin-column' ),
			__( 'Admin Column Config', 'bw-admin-column' ),
			'manage_options',
			'bw-admin-column',
			array( $this, 'bw_render_settings_page' )
		);
	}

	/**
	 * Register the setting with WordPress.
	 */
	public function bw_register_settings() {
		register_setting(
			'bw_admin_column_settings_group',
			$this->option_name,
			array(
				'type'              => 'array',
				'sanitize_callback' => array( $this, 'bw_sanitize_settings' ),
				'default'           => array(),
			)
		);
	}

	/**
	 * Enqueue settings page assets.
	 *
	 * @param string $hook Current admin page hook.
	 */
	public function bw_enqueue_settings_assets( $hook ) {
		if ( 'settings_page_bw-admin-column' !== $hook ) {
			return;
		}

		wp_enqueue_style(
			'bw-admin-column-settings',
			BW_ADMIN_COLUMN_URL . 'admin/css/bw-admin-column-settings.css',
			array(),
			BW_ADMIN_COLUMN_VERSION
		);

		wp_enqueue_script(
			'bw-admin-column-settings',
			BW_ADMIN_COLUMN_URL . 'admin/js/bw-admin-column-settings.js',
			array( 'jquery' ),
			BW_ADMIN_COLUMN_VERSION,
			true
		);

		wp_localize_script( 'bw-admin-column-settings', 'bwAdminColumnSettings', array(
			'ajaxUrl' => admin_url( 'admin-ajax.php' ),
			'nonce'   => wp_create_nonce( 'bw_admin_column_nonce' ),
			'i18n'    => array(
				'scanning' => __( 'Scanning meta keys...', 'bw-admin-column' ),
				'noKeys'   => __( 'No custom fields found for this post type.', 'bw-admin-column' ),
			),
		) );
	}

	/**
	 * Sanitize all settings before saving.
	 *
	 * @param mixed $input Raw form input.
	 * @return array Sanitized settings.
	 */
	public function bw_sanitize_settings( $input ) {
		$sanitized      = array();
		$public_post_types = $this->bw_get_public_post_types();

		if ( ! is_array( $input ) ) {
			return $sanitized;
		}

		foreach ( $public_post_types as $post_type ) {
			$pt_slug = $post_type->name;

			if ( ! isset( $input[ $pt_slug ] ) ) {
				continue;
			}

			$pt_input = $input[ $pt_slug ];

			$sanitized[ $pt_slug ] = array(
				'enabled'           => ! empty( $pt_input['enabled'] ),
				'taxonomies'        => $this->bw_sanitize_string_array( isset( $pt_input['taxonomies'] ) ? $pt_input['taxonomies'] : array() ),
				'meta_keys'         => $this->bw_sanitize_string_array( isset( $pt_input['meta_keys'] ) ? $pt_input['meta_keys'] : array() ),
				'featured_image'    => ! empty( $pt_input['featured_image'] ),
				'show_private_meta' => ! empty( $pt_input['show_private_meta'] ),
			);
		}

		return $sanitized;
	}

	/**
	 * Sanitize an array of strings.
	 *
	 * @param mixed $arr Input array.
	 * @return array Sanitized string array.
	 */
	private function bw_sanitize_string_array( $arr ) {
		if ( ! is_array( $arr ) ) {
			return array();
		}
		return array_map( 'sanitize_text_field', $arr );
	}

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

		$post_types = $this->bw_get_public_post_types();
		$settings   = get_option( $this->option_name, array() );

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : '';

		// Default to first post type if no tab or invalid tab.
		$post_type_keys = array_keys( $post_types );
		if ( empty( $active_tab ) || ! in_array( $active_tab, $post_type_keys, true ) ) {
			$active_tab = reset( $post_type_keys );
		}
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'Admin Column Configuration', 'bw-admin-column' ); ?></h1>

			<?php settings_errors( 'bw_admin_column_settings_group' ); ?>

			<nav class="nav-tab-wrapper bw-admin-column-tabs">
				<?php foreach ( $post_types as $pt ) : ?>
					<a href="<?php echo esc_url( add_query_arg( 'tab', $pt->name, admin_url( 'options-general.php?page=bw-admin-column' ) ) ); ?>"
					   class="nav-tab <?php echo $active_tab === $pt->name ? 'nav-tab-active' : ''; ?>">
						<?php echo esc_html( $pt->labels->name ); ?>
					</a>
				<?php endforeach; ?>
			</nav>

			<form method="post" action="options.php">
				<?php settings_fields( 'bw_admin_column_settings_group' ); ?>

				<?php
				// Preserve settings for inactive tabs as hidden fields.
				foreach ( $post_types as $pt ) {
					if ( $pt->name !== $active_tab ) {
						$this->bw_render_hidden_fields( $pt->name, $settings );
					}
				}
				?>

				<?php $this->bw_render_post_type_panel( $active_tab, $settings ); ?>

				<?php submit_button( __( 'Save Column Settings', 'bw-admin-column' ) ); ?>
			</form>
		</div>
		<?php
	}

	/**
	 * Render hidden fields to preserve settings for an inactive tab.
	 *
	 * @param string $post_type Post type slug.
	 * @param array  $settings  Full settings array.
	 */
	private function bw_render_hidden_fields( $post_type, $settings ) {
		$pt_settings = isset( $settings[ $post_type ] ) ? $settings[ $post_type ] : array();
		$prefix      = $this->option_name . '[' . $post_type . ']';

		if ( ! empty( $pt_settings['enabled'] ) ) {
			echo '<input type="hidden" name="' . esc_attr( $prefix . '[enabled]' ) . '" value="1" />';
		}
		if ( ! empty( $pt_settings['featured_image'] ) ) {
			echo '<input type="hidden" name="' . esc_attr( $prefix . '[featured_image]' ) . '" value="1" />';
		}
		if ( ! empty( $pt_settings['show_private_meta'] ) ) {
			echo '<input type="hidden" name="' . esc_attr( $prefix . '[show_private_meta]' ) . '" value="1" />';
		}

		$taxonomies = isset( $pt_settings['taxonomies'] ) ? $pt_settings['taxonomies'] : array();
		foreach ( $taxonomies as $tax ) {
			echo '<input type="hidden" name="' . esc_attr( $prefix . '[taxonomies][]' ) . '" value="' . esc_attr( $tax ) . '" />';
		}

		$meta_keys = isset( $pt_settings['meta_keys'] ) ? $pt_settings['meta_keys'] : array();
		foreach ( $meta_keys as $mk ) {
			echo '<input type="hidden" name="' . esc_attr( $prefix . '[meta_keys][]' ) . '" value="' . esc_attr( $mk ) . '" />';
		}
	}

	/**
	 * Render the settings panel for a specific post type.
	 *
	 * @param string $post_type Post type slug.
	 * @param array  $settings  Full settings array.
	 */
	private function bw_render_post_type_panel( $post_type, $settings ) {
		$pt_settings    = isset( $settings[ $post_type ] ) ? $settings[ $post_type ] : array();
		$enabled        = ! empty( $pt_settings['enabled'] );
		$show_private   = ! empty( $pt_settings['show_private_meta'] );
		$selected_taxes = isset( $pt_settings['taxonomies'] ) ? $pt_settings['taxonomies'] : array();
		$selected_meta  = isset( $pt_settings['meta_keys'] ) ? $pt_settings['meta_keys'] : array();
		$featured_img   = ! empty( $pt_settings['featured_image'] );

		$taxonomies   = $this->bw_get_taxonomies_for_post_type( $post_type );
		$meta_keys    = $this->bw_get_meta_keys_for_post_type( $post_type, $show_private );
		$field_prefix = $this->option_name . '[' . $post_type . ']';
		$pt_object    = get_post_type_object( $post_type );
		$pt_label     = $pt_object ? $pt_object->labels->name : $post_type;
		?>
		<div class="bw-admin-column-panel">

			<h2>
				<?php
				/* translators: %s: post type label */
				printf( esc_html__( 'Column Settings for "%s"', 'bw-admin-column' ), esc_html( $pt_label ) );
				?>
			</h2>

			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><?php esc_html_e( 'Enable Column Management', 'bw-admin-column' ); ?></th>
					<td>
						<label>
							<input type="checkbox"
							       name="<?php echo esc_attr( $field_prefix . '[enabled]' ); ?>"
							       value="1"
							       <?php checked( $enabled ); ?>
							       class="bw-admin-column-enable-toggle" />
							<?php esc_html_e( 'Manage columns for this post type', 'bw-admin-column' ); ?>
						</label>
					</td>
				</tr>
			</table>

			<div class="bw-admin-column-options" <?php echo $enabled ? '' : 'style="display:none;"'; ?>>

				<!-- Featured Image -->
				<h3><?php esc_html_e( 'Featured Image', 'bw-admin-column' ); ?></h3>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row"><?php esc_html_e( 'Show Featured Image Column', 'bw-admin-column' ); ?></th>
						<td>
							<label>
								<input type="checkbox"
								       name="<?php echo esc_attr( $field_prefix . '[featured_image]' ); ?>"
								       value="1"
								       <?php checked( $featured_img ); ?> />
								<?php esc_html_e( 'Display thumbnail with quick-change capability', 'bw-admin-column' ); ?>
							</label>
						</td>
					</tr>
				</table>

				<!-- Taxonomy Columns -->
				<h3><?php esc_html_e( 'Taxonomy Columns', 'bw-admin-column' ); ?></h3>
				<?php if ( empty( $taxonomies ) ) : ?>
					<p class="description"><?php esc_html_e( 'No public taxonomies registered for this post type.', 'bw-admin-column' ); ?></p>
				<?php else : ?>
					<fieldset class="bw-admin-column-fieldset">
						<legend class="screen-reader-text"><?php esc_html_e( 'Select taxonomy columns', 'bw-admin-column' ); ?></legend>
						<?php foreach ( $taxonomies as $tax ) : ?>
							<label class="bw-admin-column-checkbox-label">
								<input type="checkbox"
								       name="<?php echo esc_attr( $field_prefix . '[taxonomies][]' ); ?>"
								       value="<?php echo esc_attr( $tax->name ); ?>"
								       <?php checked( in_array( $tax->name, $selected_taxes, true ) ); ?> />
								<?php echo esc_html( $tax->labels->name ); ?>
								<span class="description">(<?php echo esc_html( $tax->name ); ?>)</span>
							</label>
						<?php endforeach; ?>
					</fieldset>
				<?php endif; ?>

				<!-- Custom Field Columns -->
				<h3><?php esc_html_e( 'Custom Field Columns', 'bw-admin-column' ); ?></h3>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row"><?php esc_html_e( 'Show Private Meta Keys', 'bw-admin-column' ); ?></th>
						<td>
							<label>
								<input type="checkbox"
								       name="<?php echo esc_attr( $field_prefix . '[show_private_meta]' ); ?>"
								       value="1"
								       <?php checked( $show_private ); ?>
								       class="bw-admin-column-show-private"
								       data-post-type="<?php echo esc_attr( $post_type ); ?>" />
								<?php esc_html_e( 'Include meta keys starting with _ (underscore)', 'bw-admin-column' ); ?>
							</label>
						</td>
					</tr>
				</table>

				<div class="bw-admin-column-meta-keys-list" data-post-type="<?php echo esc_attr( $post_type ); ?>">
					<?php if ( empty( $meta_keys ) ) : ?>
						<p class="description"><?php esc_html_e( 'No custom fields found for this post type. Create some posts with custom fields first.', 'bw-admin-column' ); ?></p>
					<?php else : ?>
						<fieldset>
							<legend class="screen-reader-text"><?php esc_html_e( 'Select custom field columns', 'bw-admin-column' ); ?></legend>
							<?php foreach ( $meta_keys as $meta_key ) : ?>
								<label class="bw-admin-column-checkbox-label">
									<input type="checkbox"
									       name="<?php echo esc_attr( $field_prefix . '[meta_keys][]' ); ?>"
									       value="<?php echo esc_attr( $meta_key ); ?>"
									       <?php checked( in_array( $meta_key, $selected_meta, true ) ); ?> />
									<code><?php echo esc_html( $meta_key ); ?></code>
								</label>
							<?php endforeach; ?>
						</fieldset>
					<?php endif; ?>
				</div>

			</div><!-- .bw-admin-column-options -->
		</div><!-- .bw-admin-column-panel -->
		<?php
	}

	/**
	 * Get all public post types with admin UI.
	 *
	 * @return WP_Post_Type[] Associative array of post type objects keyed by name.
	 */
	public function bw_get_public_post_types() {
		return get_post_types(
			array(
				'public'  => true,
				'show_ui' => true,
			),
			'objects'
		);
	}

	/**
	 * Get public taxonomies for a given post type.
	 *
	 * @param string $post_type Post type slug.
	 * @return WP_Taxonomy[] Filtered taxonomy objects.
	 */
	public function bw_get_taxonomies_for_post_type( $post_type ) {
		$taxonomies = get_object_taxonomies( $post_type, 'objects' );
		return array_filter( $taxonomies, function ( $tax ) {
			return $tax->public && $tax->show_ui;
		} );
	}

	/**
	 * Get distinct meta keys used by posts of a given type.
	 *
	 * @param string $post_type    Post type slug.
	 * @param bool   $show_private Whether to include keys starting with _.
	 * @return string[] Array of meta key strings.
	 */
	public function bw_get_meta_keys_for_post_type( $post_type, $show_private = false ) {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$meta_keys = $wpdb->get_col( $wpdb->prepare(
			"SELECT DISTINCT pm.meta_key
			 FROM {$wpdb->postmeta} pm
			 INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
			 WHERE p.post_type = %s
			 ORDER BY pm.meta_key
			 LIMIT 200",
			$post_type
		) );

		if ( ! $show_private ) {
			$meta_keys = array_filter( $meta_keys, function ( $key ) {
				return strpos( $key, '_' ) !== 0;
			} );
		}

		return array_values( $meta_keys );
	}

	/**
	 * Get the full settings array.
	 *
	 * @return array
	 */
	public function bw_get_settings() {
		return get_option( $this->option_name, array() );
	}

	/**
	 * Get settings for a specific post type.
	 *
	 * @param string $post_type Post type slug.
	 * @return array
	 */
	public function bw_get_post_type_settings( $post_type ) {
		$settings = $this->bw_get_settings();
		return isset( $settings[ $post_type ] ) ? $settings[ $post_type ] : array();
	}
}
