<?php
namespace R2_Offload\CLI;

use R2_Offload\Plugin;

defined( 'ABSPATH' ) || exit;

if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
	return;
}

final class Commands {

	/**
	 * Show queue + scan status.
	 *
	 * ## EXAMPLES
	 *     wp media-offload gcs status
	 */
	public function status(): void {
		$p = Plugin::instance();
		\WP_CLI::log( 'Counts: ' . wp_json_encode( $p->migrator->debug_counts() ) );
		\WP_CLI::log( 'Scan:   ' . wp_json_encode( $p->scanner->get_state() ) );
		\WP_CLI::log( 'Control:' . wp_json_encode( $p->migrator->control() ) );
	}

	/**
	 * Test GCS connection.
	 */
	public function test_connection(): void {
		$r = Plugin::instance()->storage->test_connection();
		$r['ok'] ? \WP_CLI::success( $r['message'] ) : \WP_CLI::error( $r['message'] );
	}

	/**
	 * Scan media library into the queue.
	 *
	 * [--dry-run]
	 * [--batch=<n>]
	 */
	public function scan( $args, $assoc ): void {
		$p     = Plugin::instance();
		$dry   = ! empty( $assoc['dry-run'] );
		$batch = (int) ( $assoc['batch'] ?? 200 );
		$p->scanner->start( $dry );
		while ( true ) {
			$s = $p->scanner->scan_chunk( $batch );
			\WP_CLI::log( sprintf( 'scanned=%d queued=%d skipped=%d bytes=%s finished=%d', $s['scanned'], $s['queued'], $s['skipped'], size_format( (int) $s['bytes_total'] ), $s['finished'] ) );
			if ( $s['finished'] ) break;
		}
		\WP_CLI::success( 'Scan complete.' );
	}

	/**
	 * Drain the migration queue synchronously.
	 *
	 * [--limit=<n>]
	 */
	public function migrate( $args, $assoc ): void {
		$p     = Plugin::instance();
		$limit = (int) ( $assoc['limit'] ?? 0 );
		$p->migrator->start();
		$n = 0;
		while ( true ) {
			$id = $p->migrator->process_one();
			if ( ! $id ) break;
			$n++;
			\WP_CLI::log( 'processed: ' . $id . ' (' . $n . ')' );
			if ( $limit && $n >= $limit ) break;
		}
		\WP_CLI::success( 'Processed ' . $n . ' attachments.' );
	}

	/**
	 * Retry all failed items.
	 */
	public function retry_failed(): void {
		Plugin::instance()->migrator->retry_failed();
		\WP_CLI::success( 'Failed items reset to pending.' );
	}

	/**
	 * Verify an attachment or all offloaded attachments.
	 *
	 * [--attachment-id=<id>]
	 * [--all]
	 */
	public function verify( $args, $assoc ): void {
		$p = Plugin::instance();
		if ( ! empty( $assoc['attachment-id'] ) ) {
			$r = $p->verifier->verify_attachment( (int) $assoc['attachment-id'] );
			\WP_CLI::log( wp_json_encode( $r ) );
			$r['ok'] ? \WP_CLI::success( 'OK' ) : \WP_CLI::error( 'Verification failed' );
			return;
		}
		if ( empty( $assoc['all'] ) ) {
			\WP_CLI::error( 'Pass --attachment-id=<id> or --all' );
		}
		global $wpdb;
		$ids = $wpdb->get_col( "SELECT attachment_id FROM " . \R2_Offload\DB::items_table() . " WHERE status='offloaded'" );
		$fail = 0;
		foreach ( $ids as $id ) {
			$r = $p->verifier->verify_attachment( (int) $id );
			if ( ! $r['ok'] ) {
				$fail++;
				\WP_CLI::log( 'FAIL ' . $id . ' ' . wp_json_encode( $r ) );
			}
		}
		\WP_CLI::success( sprintf( '%d verified, %d failed.', count( $ids ) - $fail, $fail ) );
	}

	/**
	 * Delete local files for verified offloaded attachments.
	 *
	 * [--dry-run]
	 * [--limit=<n>]
	 */
	public function prune( $args, $assoc ): void {
		$dry   = ! empty( $assoc['dry-run'] );
		$limit = (int) ( $assoc['limit'] ?? 0 );
		$r     = Plugin::instance()->pruner->prune( $dry, $limit );
		\WP_CLI::log( wp_json_encode( $r ) );
		\WP_CLI::success( sprintf( 'Pruned %d attachments, freed %s.', $r['pruned'], size_format( (int) $r['bytes_freed'] ) ) );
	}

	/**
	 * Restore local files from remote for an attachment.
	 *
	 * [--attachment-id=<id>]
	 */
	public function restore( $args, $assoc ): void {
		if ( empty( $assoc['attachment-id'] ) ) {
			\WP_CLI::error( 'Pass --attachment-id=<id>' );
		}
		$r = Plugin::instance()->pruner->restore( (int) $assoc['attachment-id'] );
		\WP_CLI::log( wp_json_encode( $r ) );
		$r['ok'] ? \WP_CLI::success( 'Restored.' ) : \WP_CLI::error( 'Restore failed.' );
	}

	/**
	 * Toggle URL serving source.
	 *
	 * <source>  'local' or 'remote'
	 */
	public function serve( $args ): void {
		$src = $args[0] ?? '';
		if ( ! in_array( $src, [ 'local', 'remote' ], true ) ) {
			\WP_CLI::error( 'source must be "local" or "remote"' );
		}
		Plugin::instance()->settings->update( [ 'rewrite_urls' => $src === 'remote' ? 1 : 0 ] );
		\WP_CLI::success( 'Serving from: ' . $src );
	}
}

\WP_CLI::add_command( 'media-offload gcs status',          [ Commands::class, 'status' ] );
\WP_CLI::add_command( 'media-offload gcs test-connection', [ Commands::class, 'test_connection' ] );
\WP_CLI::add_command( 'media-offload gcs scan',            [ Commands::class, 'scan' ] );
\WP_CLI::add_command( 'media-offload gcs migrate',         [ Commands::class, 'migrate' ] );
\WP_CLI::add_command( 'media-offload gcs retry-failed',    [ Commands::class, 'retry_failed' ] );
\WP_CLI::add_command( 'media-offload gcs verify',          [ Commands::class, 'verify' ] );
\WP_CLI::add_command( 'media-offload gcs prune',           [ Commands::class, 'prune' ] );
\WP_CLI::add_command( 'media-offload gcs restore',         [ Commands::class, 'restore' ] );
\WP_CLI::add_command( 'media-offload gcs serve',           [ Commands::class, 'serve' ] );
