<?php

namespace AdminColumnsCustomizer;

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

/**
 * List-table snapshot, layout (freeze/scroll), default sort, and inline-save support.
 */
final class ListTableEnhancements {

	private Module $module;

	public function __construct( Module $module ) {
		$this->module = $module;
	}

	public function registerHooks(): void {
		add_action( 'current_screen', [ $this, 'registerColumnSnapshotCapture' ] );
		add_action( 'wp_ajax_inline-save', [ $this, 'registerInlineSaveColumnHooks' ], 0 );
		add_action( 'current_screen', [ $this, 'maybeRedirectDefaultSort' ], 25 );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueueListTableAssets' ] );
	}

	public function registerColumnSnapshotCapture(): void {
		if ( ! $this->module->isEnabled() ) {
			return;
		}

		$screen = get_current_screen();
		if ( ! $screen || strpos( $screen->id, 'edit-' ) !== 0 || ! empty( $screen->taxonomy ) ) {
			return;
		}

		$post_type = str_replace( 'edit-', '', $screen->id );
		if ( ! ScreenSupport::isManageablePostType( $post_type ) ) {
			return;
		}

		$hook = $this->getPostTypeColumnsHook( $post_type );
		add_filter( $hook, [ $this, 'captureColumnSnapshot' ], 5 );
	}

	/**
	 * @param array<string, string> $columns
	 * @return array<string, string>
	 */
	public function captureColumnSnapshot( array $columns ): array {
		static $is_capturing = false;
		if ( $is_capturing ) {
			return $columns;
		}

		$screen = get_current_screen();
		if ( ! $screen || strpos( $screen->id, 'edit-' ) !== 0 || ! empty( $screen->taxonomy ) ) {
			return $columns;
		}

		$post_type = str_replace( 'edit-', '', $screen->id );
		if ( ! ScreenSupport::isManageablePostType( $post_type ) ) {
			return $columns;
		}

		$is_capturing = true;

		$config_key = ScreenSupport::configKey( 'post_type', $post_type );
		$settings   = $this->module->getModuleSettings();
		if ( ! isset( $settings['column_configs'] ) || ! is_array( $settings['column_configs'] ) ) {
			$settings['column_configs'] = [];
		}

		$snapshot = [];
		foreach ( $columns as $key => $label ) {
			if ( $key === 'cb' ) {
				continue;
			}
			$snapshot[ $key ] = wp_strip_all_tags( (string) $label );
			if ( $snapshot[ $key ] === '' ) {
				$snapshot[ $key ] = ucfirst( str_replace( [ '_', '-' ], ' ', (string) $key ) );
			}
		}

		$baseline   = $this->getBaselineColumnKeys( $post_type );
		$extra      = $settings['column_configs'][ $config_key ]['extra_columns'] ?? [];
		$new_extras = [];

		foreach ( $snapshot as $key => $label ) {
			if ( in_array( $key, $baseline, true ) ) {
				continue;
			}
			$new_extras[ $key ] = $label;
		}

		// Drop extras that disappeared (deactivated plugin).
		foreach ( array_keys( $extra ) as $key ) {
			if ( ! isset( $snapshot[ $key ] ) ) {
				unset( $extra[ $key ] );
			}
		}

		$extra = array_merge( $extra, $new_extras );

		if ( ! isset( $settings['column_configs'][ $config_key ] ) ) {
			$settings['column_configs'][ $config_key ] = [];
		}

		$existing_snapshot = $settings['column_configs'][ $config_key ]['list_snapshot'] ?? [];
		$existing_extra    = $settings['column_configs'][ $config_key ]['extra_columns'] ?? [];
		$existing_layout   = self::normalizeLayout( $settings['column_configs'][ $config_key ]['layout'] ?? [] );

		$settings['column_configs'][ $config_key ]['list_snapshot'] = $snapshot;
		$settings['column_configs'][ $config_key ]['extra_columns'] = $extra;
		$settings['column_configs'][ $config_key ]['layout']        = $existing_layout;

		if ( $existing_snapshot !== $snapshot || $existing_extra !== $extra ) {
			$this->module->saveModuleSettings( $settings );
		}

		$is_capturing = false;

		return $columns;
	}

	public function registerInlineSaveColumnHooks(): void {
		if ( ! $this->module->isEnabled() || ! wp_doing_ajax() ) {
			return;
		}

		$action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : '';
		if ( $action !== 'inline-save' ) {
			return;
		}

		$post_type = '';
		if ( isset( $_POST['post_type'] ) ) {
			$post_type = sanitize_key( wp_unslash( $_POST['post_type'] ) );
		}

		$post_id = isset( $_POST['post_ID'] ) ? absint( $_POST['post_ID'] ) : 0;
		if ( $post_type === '' && $post_id ) {
			$post_type = (string) get_post_type( $post_id );
		}

		if ( $post_type === '' || ! ScreenSupport::isManageablePostType( $post_type ) ) {
			return;
		}

		global $typenow;
		$typenow = $post_type;

		$config = $this->module->getScreenConfig( 'post_type', $post_type );
		if ( empty( $config['columns'] ) ) {
			return;
		}

		$this->module->applyPostTypeColumnHooks( $post_type, $config );
	}

	public function maybeRedirectDefaultSort(): void {
		if ( ! $this->module->isEnabled() || ! is_admin() ) {
			return;
		}

		global $pagenow;
		if ( $pagenow !== 'edit.php' ) {
			return;
		}

		if ( ! empty( $_GET['orderby'] ) || ! empty( $_GET['order'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}

		$screen = get_current_screen();
		if ( ! $screen || empty( $screen->post_type ) ) {
			return;
		}

		$post_type = $screen->post_type;
		$allowed_query_keys = $post_type === 'post' ? [] : [ 'post_type' ];
		foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( in_array( $key, $allowed_query_keys, true ) ) {
				continue;
			}
			return;
		}

		if ( ! ScreenSupport::isManageablePostType( $post_type ) ) {
			return;
		}

		$config = $this->module->getScreenConfig( 'post_type', $post_type );
		$layout = self::normalizeLayout( $config['layout'] ?? [] );
		$column = $layout['default_sort_column'] ?? '';
		if ( $column === '' || ! $this->module->isValidDefaultSortColumn( $post_type, $column, $config ) ) {
			return;
		}

		$order = in_array( $layout['default_sort_order'] ?? 'desc', [ 'asc', 'desc' ], true )
			? $layout['default_sort_order']
			: 'desc';

		$redirect_url = add_query_arg(
			[
				'orderby' => $column,
				'order'   => $order,
			],
			$post_type === 'post'
				? admin_url( 'edit.php' )
				: admin_url( 'edit.php?post_type=' . rawurlencode( $post_type ) )
		);

		wp_safe_redirect( $redirect_url );
		exit;
	}

	public function enqueueListTableAssets(): void {
		if ( ! $this->module->isEnabled() ) {
			return;
		}

		$config_key = $this->module->resolveConfigKeyFromRequest();
		if ( $config_key === null ) {
			return;
		}

		$settings = $this->module->getModuleSettings();
		$config   = $settings['column_configs'][ $config_key ] ?? null;
		if ( ! is_array( $config ) || ! $this->module->hasApplicableListConfig( $config ) ) {
			return;
		}

		$layout = self::normalizeLayout( $config['layout'] ?? [] );

		wp_enqueue_style(
			'wp-powersuite-admin-columns-list-table',
			$this->module->getAssetUrlPublic( 'list-table.css' ),
			[],
			$this->module->getVersion()
		);

		wp_enqueue_script(
			'wp-powersuite-admin-columns-list-table',
			$this->module->getAssetUrlPublic( 'list-table.js' ),
			[],
			$this->module->getVersion(),
			true
		);

		wp_localize_script(
			'wp-powersuite-admin-columns-list-table',
			'wppsAdminColumnsListTable',
			[
				'disableHorizontalScroll' => ! empty( $layout['disable_horizontal_scroll'] ),
				'freezeFirstColumns'      => (int) ( $layout['freeze_first_columns'] ?? 0 ),
				'freezeHeaderRow'         => ! empty( $layout['freeze_header_row'] ),
			]
		);
	}

	public function registerListTableWrapperMarkupHook(): void {
		add_action( 'admin_footer', [ $this, 'printListTableWrapperMarkup' ], 1 );
	}

	/**
	 * Output scroll wrapper markup in the footer, then move the list table into it immediately
	 * so layout does not jump after DOMContentLoaded (ASE pattern).
	 */
	public function printListTableWrapperMarkup(): void {
		if ( ! $this->module->isEnabled() ) {
			return;
		}

		?>
		<div class="wpps-list-table-scroll-container">
			<div id="wpps-list-table-wrapper"></div>
			<div class="wpps-list-table-scroll-shadow" aria-hidden="true"></div>
		</div>
		<script type="text/javascript">
		(function () {
			var container = document.querySelector('.wpps-list-table-scroll-container');
			var wrapper = document.getElementById('wpps-list-table-wrapper');
			var table = document.querySelector('body.wpps-acc-h-scroll .wrap .wp-list-table.widefat');
			if (!container || !wrapper || !table || wrapper.contains(table)) {
				return;
			}
			table.parentNode.insertBefore(container, table);
			wrapper.appendChild(table);
		}());
		</script>
		<?php
	}

	public function shouldDisableHorizontalScroll( array $config ): bool {
		$raw_layout = $config['layout'] ?? [];
		if ( is_array( $raw_layout ) && array_key_exists( 'disable_horizontal_scroll', $raw_layout ) ) {
			return ! empty( self::normalizeLayout( $raw_layout )['disable_horizontal_scroll'] );
		}

		foreach ( $config['columns'] ?? [] as $column ) {
			if ( ! is_array( $column ) || ! empty( $column['hidden'] ) ) {
				continue;
			}
			$width = $column['width'] ?? null;
			if ( ! empty( $width ) && $width !== 'auto' ) {
				return false;
			}
		}

		return false;
	}

	public function usesHorizontalScrollWrapper( array $config ): bool {
		return ! $this->shouldDisableHorizontalScroll( $config );
	}

	public function listTableCssSelector( array $config ): string {
		return $this->usesHorizontalScrollWrapper( $config )
			? '#wpps-list-table-wrapper .wp-list-table'
			: '.wp-list-table';
	}

	/**
	 * @param array<string, mixed> $layout
	 * @return array<string, mixed>
	 */
	public static function normalizeLayout( array $layout ): array {
		$freeze = isset( $layout['freeze_first_columns'] ) ? absint( $layout['freeze_first_columns'] ) : 0;
		if ( $freeze > 5 ) {
			$freeze = 5;
		}

		$order = isset( $layout['default_sort_order'] ) ? sanitize_key( (string) $layout['default_sort_order'] ) : 'desc';
		if ( ! in_array( $order, [ 'asc', 'desc' ], true ) ) {
			$order = 'desc';
		}

		return [
			'disable_horizontal_scroll' => ! empty( $layout['disable_horizontal_scroll'] ),
			'freeze_first_columns'      => $freeze,
			'freeze_header_row'         => ! empty( $layout['freeze_header_row'] ),
			'default_sort_column'       => sanitize_key( $layout['default_sort_column'] ?? '' ),
			'default_sort_order'        => $order,
		];
	}

	/**
	 * @param array<string, mixed> $layout
	 * @return array<string, mixed>
	 */
	public static function sanitizeLayoutInput( array $layout ): array {
		return self::normalizeLayout(
			[
				'disable_horizontal_scroll' => ! empty( $layout['disable_horizontal_scroll'] ),
				'freeze_first_columns'      => absint( $layout['freeze_first_columns'] ?? 0 ),
				'freeze_header_row'         => ! empty( $layout['freeze_header_row'] ),
				'default_sort_column'       => sanitize_key( $layout['default_sort_column'] ?? '' ),
				'default_sort_order'        => sanitize_key( $layout['default_sort_order'] ?? 'desc' ),
			]
		);
	}

	/**
	 * @return list<string>
	 */
	private function getBaselineColumnKeys( string $post_type ): array {
		if ( $post_type === 'post' ) {
			return [ 'title', 'author', 'categories', 'tags', 'comments', 'date' ];
		}

		if ( $post_type === 'page' ) {
			return [ 'title', 'author', 'comments', 'date' ];
		}

		$keys = [ 'title', 'author', 'date' ];
		if ( post_type_supports( $post_type, 'comments' ) ) {
			$keys[] = 'comments';
		}

		return $keys;
	}

	private function getPostTypeColumnsHook( string $post_type ): string {
		if ( $post_type === 'post' ) {
			return 'manage_posts_columns';
		}
		if ( $post_type === 'page' ) {
			return 'manage_pages_columns';
		}

		return "manage_{$post_type}_posts_columns";
	}
}
