<?php
/**
 * BaseCloud Boost — Media Library WebP actions
 *
 * Adds a per-image row action and a Media Library bulk action so a site owner can
 * convert SPECIFIC images to WebP on demand — e.g. just the hero/LCP image — without
 * running the full bulk converter. The bulk "Convert all" tool (Media settings)
 * remains for site-wide conversion; this is the targeted complement.
 *
 * Both paths reuse Image_Compressor::compress_attachment(), which writes a `.webp`
 * sibling for the full size and every registered thumbnail and never touches the
 * original. Image_Optimizer then serves those `.webp` files automatically.
 *
 * @package BaseCloud\Boost\Admin
 */

declare( strict_types=1 );

namespace BaseCloud\Boost\Admin;

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

use BaseCloud\Boost\Optimizer\Image_Compressor;

/**
 * Selective (per-image and selected-images) WebP conversion in the Media Library.
 */
class Media_Actions {

	private const BULK  = 'bcboost_webp';
	private const NONCE = 'bcboost_convert_webp_';

	/**
	 * Register hooks.
	 *
	 * @return void
	 */
	public function boot(): void {
		add_filter( 'bulk_actions-upload', [ $this, 'add_bulk_action' ] );
		add_filter( 'handle_bulk_actions-upload', [ $this, 'handle_bulk_action' ], 10, 3 );
		add_filter( 'media_row_actions', [ $this, 'add_row_action' ], 10, 2 );
		add_action( 'admin_post_BCBOOST_convert_image', [ $this, 'handle_row_action' ] );
		add_action( 'admin_notices', [ $this, 'render_notice' ] );
	}

	/**
	 * Whether the current user may convert images here.
	 *
	 * @return bool
	 */
	private function can_convert(): bool {
		return current_user_can( 'upload_files' ) && Image_Compressor::webp_supported();
	}

	/**
	 * Add the Media Library bulk action.
	 *
	 * @param array<string,string> $actions Registered bulk actions.
	 * @return array<string,string>
	 */
	public function add_bulk_action( array $actions ): array {
		if ( $this->can_convert() ) {
			$actions[ self::BULK ] = __( 'Convert to WebP (BaseCloud Boost)', 'basecloud-boost' );
		}
		return $actions;
	}

	/**
	 * Process the bulk action for the selected attachments.
	 *
	 * @param string $redirect Redirect URL.
	 * @param string $action   The action being taken.
	 * @param int[]  $ids      Selected attachment IDs.
	 * @return string
	 */
	public function handle_bulk_action( string $redirect, string $action, array $ids ): string {
		if ( self::BULK !== $action || ! $this->can_convert() ) {
			return $redirect;
		}

		$compressor = new Image_Compressor();
		$processed  = 0;
		$generated  = 0;
		$saved      = 0;

		foreach ( $ids as $id ) {
			$result     = $compressor->compress_attachment( (int) $id );
			$processed++;
			$generated += (int) $result['generated'];
			$saved     += (int) $result['bytes_saved'];
		}

		return add_query_arg(
			[
				'bcboost_webp_done'  => $processed,
				'bcboost_webp_gen'   => $generated,
				'bcboost_webp_saved' => $saved,
			],
			$redirect
		);
	}

	/**
	 * Add a "Convert to WebP" row action under each eligible image.
	 *
	 * @param array<string,string> $actions Row actions.
	 * @param \WP_Post              $post    Attachment post.
	 * @return array<string,string>
	 */
	public function add_row_action( array $actions, \WP_Post $post ): array {
		if ( ! $this->can_convert() ) {
			return $actions;
		}
		if ( ! in_array( (string) get_post_mime_type( $post ), [ 'image/jpeg', 'image/png' ], true ) ) {
			return $actions;
		}

		$url = wp_nonce_url(
			admin_url( 'admin-post.php?action=BCBOOST_convert_image&attachment=' . $post->ID ),
			self::NONCE . $post->ID
		);

		$actions['bcboost_webp'] = '<a href="' . esc_url( $url ) . '">'
			. esc_html__( 'Convert to WebP', 'basecloud-boost' ) . '</a>';

		return $actions;
	}

	/**
	 * Handle a single-image row-action conversion.
	 *
	 * @return void
	 */
	public function handle_row_action(): void {
		$id = isset( $_GET['attachment'] ) ? absint( $_GET['attachment'] ) : 0;
		if ( ! $id || ! $this->can_convert() ) {
			wp_die( esc_html__( 'You are not allowed to convert this image.', 'basecloud-boost' ) );
		}

		check_admin_referer( self::NONCE . $id );

		$result   = ( new Image_Compressor() )->compress_attachment( $id );
		$redirect = wp_get_referer() ?: admin_url( 'upload.php' );

		wp_safe_redirect(
			add_query_arg(
				[
					'bcboost_webp_done'  => 1,
					'bcboost_webp_gen'   => (int) $result['generated'],
					'bcboost_webp_saved' => (int) $result['bytes_saved'],
				],
				$redirect
			)
		);
		exit;
	}

	/**
	 * Show the result of a conversion as an admin notice.
	 *
	 * @return void
	 */
	public function render_notice(): void {
		if ( ! isset( $_GET['bcboost_webp_done'] ) ) {
			return;
		}

		$processed = absint( $_GET['bcboost_webp_done'] );
		$generated = isset( $_GET['bcboost_webp_gen'] ) ? absint( $_GET['bcboost_webp_gen'] ) : 0;
		$saved     = isset( $_GET['bcboost_webp_saved'] ) ? absint( $_GET['bcboost_webp_saved'] ) : 0;

		$message = sprintf(
			/* translators: 1: number of images processed, 2: WebP files generated, 3: human-readable size saved */
			esc_html__( 'BaseCloud Boost — processed %1$d image(s): generated %2$d WebP file(s), saved %3$s.', 'basecloud-boost' ),
			$processed,
			$generated,
			esc_html( size_format( $saved ) ?: '0 B' )
		);

		echo '<div class="notice notice-success is-dismissible"><p>' . $message . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- message assembled from escaped/integer parts above.
	}
}
