<?php
/**
 * Featured Image Column Module
 *
 * Adds a thumbnail column to list tables for public post types that support
 * featured images. No code runs when the module is disabled.
 *
 * @package FeaturedImageColumn
 * @since 1.0.0
 */

namespace FeaturedImageColumn;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID      = 'featured-image-column';
	private const MODULE_VERSION = '1.3.0';
	private const COLUMN_NAME    = 'wpps_featured_image';

	/** @var list<string>|null */
	private ?array $supported_post_types = null;

	/** @var array<string, mixed>|null */
	private ?array $settings_cache = null;

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Featured Image Column', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	public function getDescription(): string {
		return __( 'Thumbnail previews in post list tables for every public post type with featured images—catch missing or mismatched artwork in seconds.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return [ 'admin', 'ajax' ];
	}

	public function getDependencies(): array {
		return [];
	}

	/**
	 * @return array{enabled_post_types: list<string>}
	 */
	public static function getDefaultSettings(): array {
		return [
			'enabled_post_types' => [ 'post', 'page' ],
		];
	}

	/**
	 * Public post types that support featured images.
	 *
	 * @return list<string>
	 */
	public static function getAllowedPostTypes(): array {
		$types = [];
		foreach ( get_post_types( [ 'public' => true ], 'names' ) as $post_type ) {
			if ( $post_type === 'attachment' ) {
				continue;
			}
			if ( ! post_type_supports( $post_type, 'thumbnail' ) ) {
				continue;
			}
			$types[] = $post_type;
		}

		return $types;
	}

	protected function registerHooks(): void {
		$this->registerListTableColumns();
		add_action( 'load-edit.php', [ $this, 'registerEditScreenAssets' ] );
		add_action( 'wp_ajax_wp_powersuite_fic_set_thumbnail', [ $this, 'handleSetThumbnail' ] );
	}

	public function registerEditScreenAssets(): void {
		add_action( 'admin_head', [ $this, 'addColumnStyles' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScripts' ] );
	}

	private function registerListTableColumns(): void {
		foreach ( $this->getSupportedPostTypes() as $post_type ) {
			if ( $post_type === 'post' ) {
				add_filter( 'manage_posts_columns', [ $this, 'addColumn' ], 999 );
				add_action( 'manage_posts_custom_column', [ $this, 'renderColumn' ], 10, 2 );
				continue;
			}

			if ( $post_type === 'page' ) {
				add_filter( 'manage_pages_columns', [ $this, 'addColumn' ], 999 );
				add_action( 'manage_pages_custom_column', [ $this, 'renderColumn' ], 10, 2 );
				continue;
			}

			add_filter( "manage_{$post_type}_posts_columns", [ $this, 'addColumn' ], 999 );
			add_action( "manage_{$post_type}_posts_custom_column", [ $this, 'renderColumn' ], 10, 2 );
		}
	}

	/**
	 * @return list<string>
	 */
	private function getSupportedPostTypes(): array {
		if ( $this->supported_post_types !== null ) {
			return $this->supported_post_types;
		}

		$enabled = $this->getSettings()['enabled_post_types'] ?? [ 'post', 'page' ];
		if ( ! is_array( $enabled ) ) {
			$enabled = [ 'post', 'page' ];
		}

		$allowed = array_flip( self::getAllowedPostTypes() );
		$types   = [];

		foreach ( $enabled as $post_type ) {
			$post_type = sanitize_key( (string) $post_type );
			if ( $post_type !== '' && isset( $allowed[ $post_type ] ) ) {
				$types[] = $post_type;
			}
		}

		if ( $types === [] ) {
			foreach ( [ 'post', 'page' ] as $fallback ) {
				if ( isset( $allowed[ $fallback ] ) ) {
					$types[] = $fallback;
				}
			}
		}

		$this->supported_post_types = $types;

		return $types;
	}

	/**
	 * @return array<string, mixed>
	 */
	private function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}

		$raw                    = $this->moduleSettings()->all( [] );
		$this->settings_cache   = wp_parse_args( is_array( $raw ) ? $raw : [], self::getDefaultSettings() );

		return $this->settings_cache;
	}

	/**
	 * Add the image column as the first column (after checkbox if present).
	 *
	 * @param array<string, string> $columns Existing columns.
	 * @return array<string, string> Modified columns.
	 */
	public function addColumn( array $columns ): array {
		if ( $this->hasExistingFeaturedImageColumn( $columns ) ) {
			return $columns;
		}

		$label = isset( $columns['thumb'] )
			? __( 'Product Image', 'wp-powersuite' )
			: __( 'Image', 'wp-powersuite' );

		$new      = [];
		$inserted = false;

		foreach ( $columns as $key => $column_label ) {
			if ( $key === 'thumb' ) {
				if ( ! $inserted ) {
					$new[ self::COLUMN_NAME ] = $label;
					$inserted                 = true;
				}
				continue;
			}

			$new[ $key ] = $column_label;

			if ( $key === 'cb' && ! $inserted ) {
				$new[ self::COLUMN_NAME ] = $label;
				$inserted                 = true;
			}
		}

		if ( ! $inserted ) {
			$new = [ self::COLUMN_NAME => $label ] + $new;
		}

		return $new;
	}

	/**
	 * @param array<string, string> $columns Existing columns.
	 */
	private function hasExistingFeaturedImageColumn( array $columns ): bool {
		if ( isset( $columns[ self::COLUMN_NAME ] ) ) {
			return true;
		}

		foreach ( [ 'featured_image', 'asenha-featured-image' ] as $column_key ) {
			if ( isset( $columns[ $column_key ] ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Output the column content: clickable thumbnail or "No image" placeholder.
	 * Clicking opens the media library to set or change the featured image.
	 *
	 * @param string $column_name Column slug.
	 * @param int    $post_id     Post ID.
	 */
	public function renderColumn( string $column_name, int $post_id ): void {
		if ( $column_name !== self::COLUMN_NAME ) {
			return;
		}

		$can_edit     = current_user_can( 'edit_post', $post_id );
		$thumbnail_id = (int) get_post_thumbnail_id( $post_id );
		$url          = $thumbnail_id > 0 ? wp_get_attachment_image_url( $thumbnail_id, [ 60, 60 ] ) : '';

		if ( $can_edit ) {
			$title = $url
				? __( 'Click to change featured image', 'wp-powersuite' )
				: __( 'Click to set featured image', 'wp-powersuite' );
			echo '<button type="button" class="wpps-fic-cell" data-post-id="' . esc_attr( (string) $post_id ) . '" title="' . esc_attr( $title ) . '" aria-label="' . esc_attr( $title ) . '">';
			$this->renderThumbnailMarkup( $url, false );
			echo '</button>';
			return;
		}

		$this->renderThumbnailMarkup( $url, true );
	}

	private function renderThumbnailMarkup( string $url, bool $accessible ): void {
		if ( $url !== '' ) {
			$alt = $accessible ? esc_attr__( 'Featured image', 'wp-powersuite' ) : '';
			printf(
				'<img src="%s" alt="%s" width="40" height="40" style="width:40px;height:40px;object-fit:cover;border-radius:2px;display:block;" loading="lazy" />',
				esc_url( $url ),
				esc_attr( $alt )
			);
			return;
		}

		if ( $accessible ) {
			echo '<span class="wpps-fic-no-image" role="img" aria-label="' . esc_attr__( 'No featured image', 'wp-powersuite' ) . '"></span>';
			return;
		}

		echo '<span class="wpps-fic-no-image" aria-hidden="true"></span>';
	}

	/**
	 * Enqueue media and script for click-to-set featured image on list tables.
	 */
	public function enqueueScripts( string $hook_suffix ): void {
		if ( $hook_suffix !== 'edit.php' ) {
			return;
		}

		wp_enqueue_media();
		$handle = 'wpps-fic-column';
		wp_register_script( $handle, '', [ 'jquery', 'media-views' ], self::MODULE_VERSION, true );
		wp_enqueue_script( $handle );
		wp_add_inline_script( $handle, $this->getInlineScript() );
		wp_localize_script(
			$handle,
			'wppsFic',
			[
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'wpps_fic_set' ),
				'i18n'    => [
					'title'  => __( 'Set featured image', 'wp-powersuite' ),
					'button' => __( 'Use as featured image', 'wp-powersuite' ),
					'error'  => __( 'Could not set featured image. Please try again.', 'wp-powersuite' ),
				],
			]
		);
	}

	/**
	 * Inline script for opening media modal and updating cell on selection.
	 */
	private function getInlineScript(): string {
		return <<<'JS'
(function() {
	if (typeof jQuery === 'undefined' || typeof wp === 'undefined' || typeof wp.media === 'undefined') return;
	var frame = null;
	function openFrame(callback) {
		if (frame) {
			frame.off('select').on('select', callback);
			frame.open();
			return;
		}
		frame = wp.media({
			title: (window.wppsFic && window.wppsFic.i18n && window.wppsFic.i18n.title) || 'Set featured image',
			button: { text: (window.wppsFic && window.wppsFic.i18n && window.wppsFic.i18n.button) || 'Use as featured image' },
			library: { type: 'image' },
			multiple: false
		});
		frame.on('select', callback);
		frame.open();
	}
	jQuery(document).on('click', '.wpps-fic-cell', function(e) {
		e.preventDefault();
		var btn = jQuery(this);
		var postId = btn.data('post-id');
		if (!postId || !window.wppsFic) return;
		openFrame(function() {
			var attachment = frame.state().get('selection').first();
			if (!attachment) return;
			var attId = attachment.get('id');
			jQuery.post(window.wppsFic.ajaxUrl, {
				action: 'wp_powersuite_fic_set_thumbnail',
				nonce: window.wppsFic.nonce,
				post_id: postId,
				attachment_id: attId
			}).done(function(res) {
				if (res.success && res.data) {
					var url = res.data.url || '';
					if (url) {
						var safeUrl = url.replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
						btn.html('<img src="' + safeUrl + '" alt="" width="40" height="40" style="width:40px;height:40px;object-fit:cover;border-radius:2px;display:block;" loading="lazy" />');
					} else {
						btn.html('<span class="wpps-fic-no-image" aria-hidden="true"></span>');
					}
				} else {
					alert((window.wppsFic && window.wppsFic.i18n && window.wppsFic.i18n.error) || 'Could not set featured image.');
				}
			}).fail(function() {
				alert((window.wppsFic && window.wppsFic.i18n && window.wppsFic.i18n.error) || 'Could not set featured image.');
			});
		});
	});
})();
JS;
	}

	/**
	 * AJAX handler: set featured image for a post from the list table.
	 */
	public function handleSetThumbnail(): void {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'wpps_fic_set' ) ) {
			wp_send_json_error( [ 'message' => __( 'Security check failed.', 'wp-powersuite' ) ] );
		}

		$post_id       = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0;
		$attachment_id = isset( $_POST['attachment_id'] ) ? (int) $_POST['attachment_id'] : 0;

		if ( $post_id <= 0 || $attachment_id <= 0 ) {
			wp_send_json_error( [ 'message' => __( 'Invalid post.', 'wp-powersuite' ) ] );
		}

		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to edit this post.', 'wp-powersuite' ) ] );
		}

		$mime = get_post_mime_type( $attachment_id );
		if ( ! $mime || strpos( $mime, 'image/' ) !== 0 ) {
			wp_send_json_error( [ 'message' => __( 'Invalid image.', 'wp-powersuite' ) ] );
		}

		if ( ! set_post_thumbnail( $post_id, $attachment_id ) ) {
			wp_send_json_error( [ 'message' => __( 'Could not set featured image.', 'wp-powersuite' ) ] );
		}

		$url = wp_get_attachment_image_url( $attachment_id, [ 60, 60 ] );
		wp_send_json_success( [ 'url' => $url ?: '' ] );
	}

	/**
	 * Add minimal CSS for the column width and No Image placeholder (list tables only).
	 */
	public function addColumnStyles(): void {
		?>
		<style type="text/css">
			.wp-list-table .column-<?php echo esc_attr( self::COLUMN_NAME ); ?>,
			.wp-list-table th.column-<?php echo esc_attr( self::COLUMN_NAME ); ?>,
			.wp-list-table td.column-<?php echo esc_attr( self::COLUMN_NAME ); ?> {
				width: 52px;
				max-width: 52px;
				text-align: center;
				vertical-align: middle;
			}
			.wp-list-table td.column-<?php echo esc_attr( self::COLUMN_NAME ); ?> .wpps-fic-no-image {
				display: inline-block;
				width: 40px;
				height: 40px;
				background: #f0f0f1;
				border: 1px dashed #c3c4c7;
				border-radius: 2px;
				box-sizing: border-box;
			}
			.wp-list-table td.column-<?php echo esc_attr( self::COLUMN_NAME ); ?> .wpps-fic-no-image::before {
				content: "";
				display: block;
				width: 100%;
				height: 100%;
				background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23c3c4c7'%3E%3Cpath d='M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z'/%3E%3C/svg%3E") center center / 24px 24px no-repeat;
			}
			.wp-list-table td.column-<?php echo esc_attr( self::COLUMN_NAME ); ?> .wpps-fic-cell {
				display: inline-block;
				padding: 0;
				margin: 0;
				border: none;
				background: none;
				cursor: pointer;
				border-radius: 2px;
				line-height: 0;
			}
			.wp-list-table td.column-<?php echo esc_attr( self::COLUMN_NAME ); ?> .wpps-fic-cell:hover {
				opacity: 0.85;
			}
		</style>
		<?php
	}
}
