<?php
/**
 * Media Library list table columns.
 *
 * @package AIAltTextGenerator
 * @since 1.5.0
 */

namespace AIAltTextGenerator;

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

/**
 * @since 1.5.0
 */
class MediaColumns {

	public function register(): void {
		if ( ! Capabilities::canView() ) {
			return;
		}

		add_filter( 'manage_media_columns', [ $this, 'addColumns' ] );
		add_action( 'manage_media_custom_column', [ $this, 'renderColumn' ], 10, 2 );
		add_action( 'restrict_manage_posts', [ $this, 'renderFilter' ], 10, 2 );
		add_action( 'pre_get_posts', [ $this, 'filterQuery' ] );
		add_filter( 'ajax_query_attachments_args', [ $this, 'filterGridQuery' ] );
	}

	/** @param array<string, string> $columns */
	public function addColumns( array $columns ): array {
		if ( ! $this->isMediaLibraryScreen() ) {
			return $columns;
		}

		$new = [];
		foreach ( $columns as $key => $label ) {
			$new[ $key ] = $label;
			if ( $key === 'parent' ) {
				$new['wpps_ai_alt_status'] = __( 'Alt status', 'wp-powersuite' );
				$new['wpps_ai_alt_text']   = __( 'Alt text', 'wp-powersuite' );
			}
		}

		if ( ! isset( $new['wpps_ai_alt_status'] ) ) {
			$new['wpps_ai_alt_status'] = __( 'Alt status', 'wp-powersuite' );
			$new['wpps_ai_alt_text']   = __( 'Alt text', 'wp-powersuite' );
		}

		return $new;
	}

	/**
	 * @param string|int $post_id Attachment ID.
	 */
	public function renderColumn( string $column, $post_id ): void {
		if ( ! $this->isMediaLibraryScreen() ) {
			return;
		}

		$attachment_id = (int) $post_id;
		if ( $attachment_id <= 0 ) {
			return;
		}

		if ( ! in_array( $column, [ 'wpps_ai_alt_status', 'wpps_ai_alt_text' ], true ) ) {
			return;
		}

		if ( ! AltTextGenerator::isSupportedImage( $attachment_id ) ) {
			echo '<span class="description">—</span>';
			return;
		}

		if ( $column === 'wpps_ai_alt_status' ) {
			$status = AttachmentStatus::resolve( $attachment_id );
			printf(
				'<span class="wpps-ai-alt-badge %1$s">%2$s</span>',
				esc_attr( AttachmentStatus::badgeClass( $status['slug'] ) ),
				esc_html( $status['label'] )
			);
			if ( Capabilities::canGenerate() && Settings::hasApiKey() && in_array( $status['slug'], [ 'missing', 'weak', 'too_short', 'keyword_stuffed', 'needs_review' ], true ) ) {
				printf(
					'<br><button type="button" class="button button-small wpps-ai-alt-col-generate" data-attachment-id="%1$s">%2$s</button>',
					esc_attr( (string) (int) $attachment_id ),
					esc_html__( 'Generate', 'wp-powersuite' )
				);
			}
			if ( Capabilities::canGenerate() && $status['slug'] === 'decorative' ) {
				printf(
					'<br><button type="button" class="button button-small wpps-ai-alt-col-undecorative" data-attachment-id="%1$s">%2$s</button>',
					esc_attr( (string) (int) $attachment_id ),
					esc_html__( 'Unmark decorative', 'wp-powersuite' )
				);
			}
			return;
		}

		$alt = (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
		if ( $alt === '' ) {
			$suggestion = AttachmentMeta::getSuggestion( $attachment_id );
			if ( $suggestion !== '' ) {
				echo '<span class="description">' . esc_html( self::truncate( $suggestion, 80 ) ) . '</span>';
				echo '<br><em class="description">' . esc_html__( '(suggestion)', 'wp-powersuite' ) . '</em>';
			} else {
				echo '<span class="description">—</span>';
			}
			return;
		}

		echo esc_html( self::truncate( $alt, 80 ) );
	}

	public function renderFilter( string $post_type, string $which ): void {
		if ( $post_type !== 'attachment' || $which !== 'top' || ! $this->isMediaLibraryScreen() ) {
			return;
		}

		$current = isset( $_GET['wpps_ai_alt_filter'] ) ? sanitize_key( wp_unslash( $_GET['wpps_ai_alt_filter'] ) ) : '';
		$options = [
			''             => __( 'All alt statuses', 'wp-powersuite' ),
			'missing'      => __( 'Missing alt text', 'wp-powersuite' ),
			'weak'         => __( 'Weak alt text', 'wp-powersuite' ),
			'needs_review' => __( 'Needs review', 'wp-powersuite' ),
			'decorative'   => __( 'Decorative', 'wp-powersuite' ),
			'duplicates'   => __( 'Duplicate alt text', 'wp-powersuite' ),
			'good'         => __( 'Looks good', 'wp-powersuite' ),
		];
		?>
		<label for="wpps-ai-alt-filter" class="screen-reader-text"><?php esc_html_e( 'Filter by alt text status', 'wp-powersuite' ); ?></label>
		<select name="wpps_ai_alt_filter" id="wpps-ai-alt-filter">
			<?php foreach ( $options as $value => $label ) : ?>
				<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $current, $value ); ?>><?php echo esc_html( $label ); ?></option>
			<?php endforeach; ?>
		</select>
		<?php
	}

	public function filterQuery( \WP_Query $query ): void {
		if ( ! is_admin() || ! $query->is_main_query() || ! $this->isMediaLibraryScreen() ) {
			return;
		}

		$filter = isset( $_GET['wpps_ai_alt_filter'] ) ? sanitize_key( wp_unslash( $_GET['wpps_ai_alt_filter'] ) ) : '';
		if ( $filter === '' ) {
			return;
		}

		if ( $filter === 'duplicates' ) {
			$ids = DuplicateDetector::getDuplicateAttachmentIds();
			$query->set( 'post__in', $ids !== [] ? $ids : [ 0 ] );
			return;
		}

		$meta_query = $query->get( 'meta_query' );
		if ( ! is_array( $meta_query ) ) {
			$meta_query = [];
		}

		$meta_query = array_merge( $meta_query, self::metaQueryForFilter( $filter ) );
		$query->set( 'meta_query', $meta_query );
	}

	/** @param array<string, mixed> $args */
	public function filterGridQuery( array $args ): array {
		if ( ! $this->isMediaLibraryScreen() ) {
			return $args;
		}

		$filter = isset( $_REQUEST['wpps_ai_alt_filter'] ) ? sanitize_key( wp_unslash( $_REQUEST['wpps_ai_alt_filter'] ) ) : '';
		if ( $filter === '' ) {
			return $args;
		}

		if ( $filter === 'duplicates' ) {
			$ids = DuplicateDetector::getDuplicateAttachmentIds();
			$args['post__in'] = $ids !== [] ? $ids : [ 0 ];
			return $args;
		}

		$meta_query = isset( $args['meta_query'] ) && is_array( $args['meta_query'] ) ? $args['meta_query'] : [];
		// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Media Library filter for missing/weak alt text.
		$args['meta_query'] = array_merge( $meta_query, self::metaQueryForFilter( $filter ) );

		return $args;
	}

	private function isMediaLibraryScreen(): bool {
		if ( ! is_admin() ) {
			return false;
		}

		global $pagenow;

		if ( isset( $pagenow ) && $pagenow === 'upload.php' ) {
			return true;
		}

		// Grid AJAX: only treat as Media Library when the request came from upload.php.
		if ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) {
			$action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( (string) $_REQUEST['action'] ) ) : '';
			if ( $action !== 'query-attachments' ) {
				return false;
			}

			if ( empty( $_SERVER['HTTP_REFERER'] ) ) {
				return false;
			}

			$referer = wp_parse_url( wp_unslash( (string) $_SERVER['HTTP_REFERER'] ) );
			$path    = is_array( $referer ) ? (string) ( $referer['path'] ?? '' ) : '';

			return $path !== '' && ( str_ends_with( $path, '/upload.php' ) || str_ends_with( $path, 'upload.php' ) );
		}

		return false;
	}

	private static function truncate( string $text, int $max ): string {
		if ( function_exists( 'mb_strlen' ) && function_exists( 'mb_substr' ) ) {
			return mb_strlen( $text ) > $max ? mb_substr( $text, 0, $max - 1 ) . '…' : $text;
		}

		return strlen( $text ) > $max ? substr( $text, 0, $max - 1 ) . '…' : $text;
	}

	/** @return list<array<string, mixed>> */
	private static function metaQueryForFilter( string $filter ): array {
		switch ( $filter ) {
			case 'missing':
				return [
					'relation' => 'AND',
					[
						'relation' => 'OR',
						[
							'key'     => '_wp_attachment_image_alt',
							'compare' => 'NOT EXISTS',
						],
						[
							'key'     => '_wp_attachment_image_alt',
							'value'   => '',
							'compare' => '=',
						],
					],
					[
						'relation' => 'OR',
						[
							'key'     => AttachmentMeta::META_DECORATIVE,
							'compare' => 'NOT EXISTS',
						],
						[
							'key'     => AttachmentMeta::META_DECORATIVE,
							'value'   => '1',
							'compare' => '!=',
						],
					],
				];

			case 'needs_review':
				return [
					[
						'key'     => AttachmentMeta::META_STATUS,
						'value'   => [ 'generated', 'needs_review' ],
						'compare' => 'IN',
					],
				];

			case 'decorative':
				return [
					[
						'key'   => AttachmentMeta::META_DECORATIVE,
						'value' => '1',
					],
				];

			case 'weak':
				return [
					'relation' => 'AND',
					[
						'key'     => '_wp_attachment_image_alt',
						'value'   => '',
						'compare' => '!=',
					],
					[
						'key'     => '_wp_attachment_image_alt',
						'value'   => QualityScorer::weakExactWords(),
						'compare' => 'IN',
					],
				];

			case 'good':
				return [
					'relation' => 'AND',
					[
						'key'     => '_wp_attachment_image_alt',
						'value'   => '',
						'compare' => '!=',
					],
					[
						'key'     => '_wp_attachment_image_alt',
						'value'   => QualityScorer::weakExactWords(),
						'compare' => 'NOT IN',
					],
				];

			case 'duplicates':
				return [];
		}

		return [];
	}
}
