<?php
/**
 * Media Library list table integration.
 *
 * @package VacuumImageOptimizer\Media
 */

namespace VacuumImageOptimizer\Media;

use VacuumImageOptimizer\Settings\CompressionSettings;
use VacuumImageOptimizer\Utils\ImageFormat;

defined( 'ABSPATH' ) || exit;

/**
 * Adds optimization information to the Media Library list table.
 */
class LibraryIntegration {

	/**
	 * Whether Media Library hooks have already been registered.
	 *
	 * @var bool
	 */
	private bool $registered = false;

	/**
	 * Register Media Library hooks.
	 *
	 * @return void
	 */
	public function register(): void {
		if ( $this->registered ) {
			return;
		}

		$this->registered = true;

		add_filter( 'manage_media_columns', [ $this, 'add_columns' ] );
		add_filter( 'manage_upload_columns', [ $this, 'add_columns' ] );
		add_action( 'manage_media_custom_column', [ $this, 'render_column' ], 10, 2 );
		add_action( 'manage_upload_custom_column', [ $this, 'render_column' ], 10, 2 );
	}

	/**
	 * Add optimization columns to the Media Library.
	 *
	 * @param array<string, string> $columns Existing columns.
	 * @return array<string, string>
	 */
	public function add_columns( array $columns ): array {
		$vacimg_columns = [
			'vacimg_image_optimizer' => __( 'Vacuum', 'vacuum-image-optimizer' ),
		];

		$updated_columns = [];
		$inserted        = false;

		foreach ( $columns as $key => $label ) {
			$updated_columns[ $key ] = $label;

			if ( 'title' === $key ) {
				$updated_columns = array_merge( $updated_columns, $vacimg_columns );
				$inserted        = true;
			}
		}

		if ( ! $inserted ) {
			$updated_columns = array_merge( $updated_columns, $vacimg_columns );
		}

		return $updated_columns;
	}

	/**
	 * Render a custom Media Library column.
	 *
	 * @param string $column_name Column name.
	 * @param int    $attachment_id Attachment ID.
	 * @return void
	 */
	public function render_column( string $column_name, int $attachment_id ): void {
		if ( 'vacimg_image_optimizer' !== $column_name ) {
			return;
		}

		// Generated WebP/AVIF derivatives get a clear, compact provenance indicator.
		$generated_by = sanitize_key( (string) get_post_meta( $attachment_id, '_vacimg_generated_by', true ) );
		if ( '' !== $generated_by ) {
			$this->render_generated_indicator( $attachment_id, $generated_by );
			return;
		}

		$data = $this->get_column_data( $attachment_id );

		$rows = [
			__( 'Status', 'vacuum-image-optimizer' )   => $data['status_label'],
			__( 'Original', 'vacuum-image-optimizer' ) => $data['original_size'],
			__( 'WebP', 'vacuum-image-optimizer' )     => $data['webp_size'],
			__( 'AVIF', 'vacuum-image-optimizer' )     => $data['avif_size'],
			__( 'Saved %', 'vacuum-image-optimizer' )  => $data['saved_percent'],
			__( 'Saved KB', 'vacuum-image-optimizer' ) => $data['saved_kb'],
		];

		echo '<div class="vacimg-media-status">';

		foreach ( $rows as $label => $value ) {
			printf(
				'<div class="vacimg-media-status__row"><strong>%1$s</strong><span>%2$s</span></div>',
				esc_html( $label ),
				esc_html( $value )
			);
		}

		if ( $data['message'] ) {
			printf(
				'<div class="vacimg-media-message">%s</div>',
				esc_html( $data['message'] )
			);
		}

		$this->render_inline_actions( $attachment_id, $data );

		echo '</div>';
	}

	/**
	 * Render a compact "generated by Vacuum Image Optimizer" indicator.
	 *
	 * @param int    $attachment_id Derivative attachment ID.
	 * @param string $generated_by Derivative format key (webp/avif).
	 * @return void
	 */
	private function render_generated_indicator( int $attachment_id, string $generated_by ): void {
		$labels    = [
			'webp' => __( 'WebP', 'vacuum-image-optimizer' ),
			'avif' => __( 'AVIF', 'vacuum-image-optimizer' ),
		];
		$format    = $labels[ $generated_by ] ?? strtoupper( $generated_by );
		$source_id = absint( get_post_meta( $attachment_id, '_vacimg_source_attachment_id', true ) );

		echo '<div class="vacimg-media-status">';
		printf(
			'<div class="vacimg-media-status__row"><strong>%1$s</strong><span>%2$s</span></div>',
			esc_html__( 'Generated by', 'vacuum-image-optimizer' ),
			esc_html__( 'Vacuum Image Optimizer', 'vacuum-image-optimizer' )
		);
		printf(
			'<div class="vacimg-media-status__row"><strong>%1$s</strong><span>%2$s</span></div>',
			esc_html__( 'Format', 'vacuum-image-optimizer' ),
			esc_html( $format )
		);

		if ( $source_id > 0 ) {
			printf(
				'<div class="vacimg-media-status__row"><strong>%1$s</strong><span>%2$s</span></div>',
				esc_html__( 'Source', 'vacuum-image-optimizer' ),
				esc_html( get_the_title( $source_id ) )
			);
		}

		echo '</div>';
	}

	/**
	 * Get compact column data for an attachment.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return array<string, string>
	 */
	private function get_column_data( int $attachment_id ): array {
		$status = (string) get_post_meta( $attachment_id, '_vacimg_status', true );
		$status = '' === $status ? 'pending' : sanitize_key( $status );
		$auto_status = sanitize_key( (string) get_post_meta( $attachment_id, '_vacimg_auto_status', true ) );
		$mime   = ImageFormat::get_attachment_mime_type( $attachment_id );

		if ( 'pending' === $status && CompressionSettings::is_mime_excluded( $mime ) ) {
			$status = 'excluded';
		} elseif ( 'pending' === $status && ! ImageFormat::is_supported_source_attachment( $attachment_id ) ) {
			$status = 'unsupported';
		}

		$data = [
			'status_label'  => __( 'Not optimized', 'vacuum-image-optimizer' ),
			'original_size' => $this->get_original_size_label( $attachment_id ),
			'webp_size'     => $this->get_placeholder(),
			'avif_size'     => $this->format_meta_size( $attachment_id, '_vacimg_avif_size', $this->get_placeholder() ),
			'saved_percent' => $this->get_placeholder(),
			'saved_kb'      => $this->get_placeholder(),
			'message'       => '',
		];

		if ( 'optimized' === $status ) {
			$data['status_label']  = 'optimized' === $auto_status
				? __( 'Optimized automatically', 'vacuum-image-optimizer' )
				: __( 'Optimized', 'vacuum-image-optimizer' );
			$data['original_size'] = $this->format_meta_size( $attachment_id, '_vacimg_source_size', $data['original_size'] );
			$data['webp_size']     = $this->format_meta_size( $attachment_id, '_vacimg_webp_size', $this->get_placeholder() );
			$data['saved_percent'] = $this->get_saved_percent_label( $attachment_id );
			$data['saved_kb']      = $this->get_saved_kb_label( $attachment_id );

			return $data;
		}

		if ( 'excluded' === $status ) {
			$data['status_label'] = 'skipped' === $auto_status
				? __( 'Skipped by exclusion', 'vacuum-image-optimizer' )
				: __( 'Excluded', 'vacuum-image-optimizer' );
			$data['message']      = ImageFormat::get_skip_reason( $attachment_id );

			return $data;
		}

		if ( in_array( $status, [ 'unsupported', 'skipped' ], true ) ) {
			$data['status_label'] = __( 'Skipped', 'vacuum-image-optimizer' );
			$data['message']      = $this->get_short_error_message( $attachment_id ) ?: ImageFormat::get_skip_reason( $attachment_id );

			return $data;
		}

		if ( 'error' === $status ) {
			$data['status_label'] = 'failed' === $auto_status
				? __( 'Failed, retry available', 'vacuum-image-optimizer' )
				: __( 'Error', 'vacuum-image-optimizer' );
			$data['message']      = $this->get_short_error_message( $attachment_id );

			return $data;
		}

		if ( 'pending' === $status && 'pending' === $auto_status ) {
			$data['status_label'] = __( 'Pending automatic optimization', 'vacuum-image-optimizer' );
		}

		return $data;
	}

	/**
	 * Get the original file size label for an attachment.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return string
	 */
	private function get_original_size_label( int $attachment_id ): string {
		$file_path = get_attached_file( $attachment_id );

		if ( ! is_string( $file_path ) || '' === $file_path || ! file_exists( $file_path ) ) {
			return $this->get_placeholder();
		}

		$file_size = filesize( $file_path );

		if ( false === $file_size ) {
			return $this->get_placeholder();
		}

		return size_format( (int) $file_size, 2 );
	}

	/**
	 * Format a numeric size stored in attachment meta.
	 *
	 * @param int    $attachment_id Attachment ID.
	 * @param string $meta_key Meta key.
	 * @param string $fallback Fallback label.
	 * @return string
	 */
	private function format_meta_size( int $attachment_id, string $meta_key, string $fallback ): string {
		$value = get_post_meta( $attachment_id, $meta_key, true );
		$size  = is_numeric( $value ) ? absint( $value ) : 0;

		return $size > 0 ? size_format( $size, 2 ) : $fallback;
	}

	/**
	 * Get the saved label for optimized attachments.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return string
	 */
	private function get_saved_kb_label( int $attachment_id ): string {
		$bytes = get_post_meta( $attachment_id, '_vacimg_savings_bytes', true );

		$bytes_value = is_numeric( $bytes ) ? absint( $bytes ) : 0;

		return $bytes_value > 0 ? size_format( $bytes_value, 2 ) : $this->get_placeholder();
	}

	/**
	 * Get the saved percentage label for optimized attachments.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return string
	 */
	private function get_saved_percent_label( int $attachment_id ): string {
		$percent = get_post_meta( $attachment_id, '_vacimg_savings_percent', true );

		$percent_value = is_numeric( $percent ) ? (float) $percent : 0.0;

		return $percent_value > 0 ? number_format_i18n( $percent_value, 2 ) . '%' : $this->get_placeholder();
	}

	/**
	 * Get a short stored error message.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return string
	 */
	private function get_short_error_message( int $attachment_id ): string {
		$message = get_post_meta( $attachment_id, '_vacimg_error_message', true );
		$message = is_string( $message ) ? trim( $message ) : '';

		if ( '' === $message ) {
			return '';
		}

		return wp_html_excerpt( $message, 80, '…' );
	}

	/**
	 * Get a consistent placeholder for missing optimization data.
	 *
	 * @return string
	 */
	private function get_placeholder(): string {
		return '—';
	}

	/**
	 * Render compact action buttons in the Vacuum column.
	 *
	 * @param int                  $attachment_id Attachment ID.
	 * @param array<string,string> $data Column data.
	 * @return void
	 */
	private function render_inline_actions( int $attachment_id, array $data ): void {
		if ( ! current_user_can( 'upload_files' ) || ! ImageFormat::is_supported_source_attachment( $attachment_id ) ) {
			return;
		}

		$actions = [
			'vacimg_optimize_image' => __( 'Optimize', 'vacuum-image-optimizer' ),
			'vacimg_generate_webp'  => __( 'Generate WebP', 'vacuum-image-optimizer' ),
		];

		if ( CompressionSettings::is_avif_enabled() ) {
			$actions['vacimg_generate_avif'] = __( 'AVIF', 'vacuum-image-optimizer' );
		}

		$backup_path = get_post_meta( $attachment_id, '_vacimg_backup_path', true );
		if ( is_string( $backup_path ) && '' !== $backup_path ) {
			$actions['vacimg_restore_original'] = __( 'Restore', 'vacuum-image-optimizer' );
		}

		echo '<div class="vacimg-media-actions">';
		foreach ( $actions as $action => $label ) {
			$url = wp_nonce_url(
				admin_url( 'admin.php?action=' . sanitize_key( $action ) . '&attachment_id=' . absint( $attachment_id ) ),
				$action . '_' . absint( $attachment_id )
			);

			printf(
				'<a class="vacimg-media-action" href="%1$s">%2$s</a>',
				esc_url( $url ),
				esc_html( $label )
			);
		}
		echo '</div>';
	}
}
