<?php
/**
 * Self-Destruct CLI Command.
 *
 * @package Activitypub
 */

namespace Activitypub\Cli;

use Activitypub\Activity\Activity;
use Activitypub\Collection\Actors;
use Activitypub\Collection\Outbox;
use Activitypub\Collection\Posts;

use function Activitypub\add_to_outbox;

/**
 * Remove the blog from the Fediverse.
 *
 * @package Activitypub
 */
class Self_Destruct_Command extends \WP_CLI_Command {

	/**
	 * Remove the entire blog from the Fediverse.
	 *
	 * This command permanently removes your blog from ActivityPub networks by sending
	 * Delete activities to all followers. This action is IRREVERSIBLE.
	 *
	 * ## OPTIONS
	 *
	 * [--status]
	 * : Check the status of the self-destruct process instead of running it.
	 * Use this to monitor progress after initiating the deletion process.
	 *
	 * [--yes]
	 * : Skip the confirmation prompt and proceed with deletion immediately.
	 * Use with extreme caution as this bypasses all safety checks.
	 *
	 * ## EXAMPLES
	 *
	 *     # Start the self-destruct process (with confirmation prompt)
	 *     $ wp activitypub self-destruct
	 *
	 *     # Check the status of an ongoing self-destruct process
	 *     $ wp activitypub self-destruct --status
	 *
	 *     # Force deletion without confirmation (dangerous!)
	 *     $ wp activitypub self-destruct --yes
	 *
	 * ## WHAT THIS DOES
	 *
	 * - Finds all users with ActivityPub capabilities
	 * - Creates Delete activities for each user
	 * - Sends these activities to all followers
	 * - Removes your blog from ActivityPub discovery
	 * - Sets a flag to track completion status
	 *
	 * ## IMPORTANT NOTES
	 *
	 * - This action cannot be undone
	 * - Keep the ActivityPub plugin active during the process
	 * - The process may take several minutes to complete
	 * - You will be notified when the process finishes
	 *
	 * @param array $args       The positional arguments (unused).
	 * @param array $assoc_args The associative arguments (--status, --yes).
	 */
	public function __invoke( $args, $assoc_args = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
		// Check if --status flag is provided.
		if ( isset( $assoc_args['status'] ) ) {
			$this->show_self_destruct_status();
			return;
		}

		// Check if self-destruct has already been run.
		if ( \get_option( 'activitypub_self_destruct' ) ) {
			\WP_CLI::error( 'Self-destruct has already been initiated. The process may still be running or has completed.' . PHP_EOL . \WP_CLI::colorize( 'To check the status, run: %Bwp activitypub self-destruct --status%n' ) );
			return;
		}

		$this->execute_self_destruct( $assoc_args );
	}

	/**
	 * Execute the self-destruct process.
	 *
	 * This method handles the actual deletion process:
	 * 1. Displays warning and confirmation prompt
	 * 2. Retrieves all ActivityPub-capable users
	 * 3. Creates and schedules Delete activities for each user
	 * 4. Sets the self-destruct flag for status tracking
	 * 5. Provides progress feedback and completion instructions
	 *
	 * @param array $assoc_args The associative arguments from WP-CLI.
	 */
	private function execute_self_destruct( $assoc_args ) {
		$this->display_self_destruct_warning();
		\WP_CLI::confirm( 'Are you absolutely sure you want to continue?', $assoc_args );

		$user_ids = $this->get_activitypub_users();
		if ( empty( $user_ids ) ) {
			\WP_CLI::warning( 'No ActivityPub users found. Nothing to delete.' );
			return;
		}

		$processed = $this->process_user_deletions( $user_ids );

		// Delete all remote posts.
		$deleted_posts = Posts::delete_all();
		if ( $deleted_posts > 0 ) {
			\WP_CLI::line( \WP_CLI::colorize( "%G✓%n Deleted {$deleted_posts} remote post(s)." ) );
		}

		$this->display_completion_message( $processed );
	}

	/**
	 * Display the self-destruct warning message.
	 */
	private function display_self_destruct_warning() {
		\WP_CLI::line( \WP_CLI::colorize( '%R⚠️  DESTRUCTIVE OPERATION ⚠️%n' ) );
		\WP_CLI::line( '' );

		$question = 'You are about to delete your blog from the Fediverse. This action is IRREVERSIBLE and will:';
		\WP_CLI::line( \WP_CLI::colorize( "%y{$question}%n" ) );
		\WP_CLI::line( \WP_CLI::colorize( '%y• Send Delete activities to all followers%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( '%y• Remove your blog from ActivityPub networks%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( '%y• Delete all cached remote posts%n' ) );
		\WP_CLI::line( '' );
	}

	/**
	 * Get all users with ActivityPub capabilities.
	 *
	 * @return array Array of user IDs with ActivityPub capabilities.
	 */
	private function get_activitypub_users() {
		return \get_users(
			array(
				'fields'         => 'ID',
				'capability__in' => array( 'activitypub' ),
			)
		);
	}

	/**
	 * Process user deletions and create Delete activities.
	 *
	 * @param array $user_ids Array of user IDs to process.
	 *
	 * @return int Number of users successfully processed.
	 */
	private function process_user_deletions( $user_ids ) {
		$user_count = \count( $user_ids );
		\WP_CLI::line( \WP_CLI::colorize( '%GStarting Fediverse deletion process...%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( "%BFound {$user_count} ActivityPub user(s) to process:%n" ) );
		\WP_CLI::line( '' );

		// Set the self-destruct flag.
		\update_option( 'activitypub_self_destruct', true );

		$processed = 0;
		foreach ( $user_ids as $user_id ) {
			if ( $this->create_delete_activity_for_user( $user_id, $processed, $user_count ) ) {
				++$processed;
			}
		}

		\WP_CLI::line( '' );

		if ( 0 === $processed ) {
			\WP_CLI::error( 'Failed to schedule any deletions. Please check your configuration.' );
		}

		return $processed;
	}

	/**
	 * Create a Delete activity for a specific user.
	 *
	 * @param int $user_id    The user ID to process.
	 * @param int $processed  Number of users already processed.
	 * @param int $user_count Total number of users to process.
	 *
	 * @return bool True if the activity was created successfully, false otherwise.
	 */
	private function create_delete_activity_for_user( $user_id, $processed, $user_count ) {
		$actor = Actors::get_by_id( $user_id );

		if ( ! $actor ) {
			\WP_CLI::line( \WP_CLI::colorize( "%R✗ Failed to load user ID: {$user_id}%n" ) );
			return false;
		}

		$activity = new Activity();
		$activity->set_actor( $actor->get_id() );
		$activity->set_object( $actor->get_id() );
		$activity->set_type( 'Delete' );

		$result = add_to_outbox( $activity, null, $user_id );
		if ( \is_wp_error( $result ) ) {
			\WP_CLI::line( \WP_CLI::colorize( "%R✗ Failed to schedule deletion for: %B{$actor->get_name()}%n - {$result->get_error_message()}" ) );
			return false;
		}

		$current = $processed + 1;
		\WP_CLI::line( \WP_CLI::colorize( "%G✓%n [{$current}/{$user_count}] Scheduled deletion for: %B{$actor->get_name()}%n" ) );
		return true;
	}

	/**
	 * Display the completion message after processing.
	 *
	 * @param int $processed Number of users successfully processed.
	 */
	private function display_completion_message( $processed ) {
		if ( 0 === $processed ) {
			return; // Error already displayed in process_user_deletions.
		}

		\WP_CLI::success( "Successfully scheduled {$processed} user(s) for Fediverse deletion." );
		\WP_CLI::line( '' );
		\WP_CLI::line( \WP_CLI::colorize( '%Y📋 Next Steps:%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( '%Y• Keep the ActivityPub plugin active%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( '%Y• Delete activities will be sent automatically%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( '%Y• Process may take several minutes to complete%n' ) );
		\WP_CLI::line( \WP_CLI::colorize( '%Y• The plugin will notify you when the process is done.%n' ) );
		\WP_CLI::line( '' );
	}

	/**
	 * Show the status of the self-destruct process.
	 *
	 * Checks the current state of the self-destruct process by:
	 * - Verifying if the process has been initiated
	 * - Counting remaining pending Delete activities
	 * - Displaying appropriate status messages and progress
	 * - Providing guidance on next steps
	 *
	 * Status can be:
	 * - NOT STARTED: Process hasn't been initiated
	 * - IN PROGRESS: Delete activities are still being processed
	 * - COMPLETED: All Delete activities have been sent
	 */
	private function show_self_destruct_status() {
		// Only proceed if self-destruct is active.
		if ( ! \get_option( 'activitypub_self_destruct', false ) ) {
			\WP_CLI::line( \WP_CLI::colorize( '%C❌ Status: NOT STARTED%n' ) );
			\WP_CLI::line( \WP_CLI::colorize( '%CThe self-destruct process has not been initiated.%n' ) );
			\WP_CLI::line( '' );
			\WP_CLI::line( \WP_CLI::colorize( '%CTo start the process, run:%n %Bwp activitypub self-destruct%n' ) );
			\WP_CLI::line( '' );
			return;
		}

		\WP_CLI::line( \WP_CLI::colorize( '%B🔍 Self-Destruct Status Check%n' ) );
		\WP_CLI::line( '' );

		// Check if there are any more pending Delete activities for self-destruct.
		$pending_deletes = \get_posts(
			array(
				'post_type'      => Outbox::POST_TYPE,
				'post_status'    => 'pending',
				'posts_per_page' => -1,
				'fields'         => 'ids',
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
				'meta_query'     => array(
					array(
						'key'   => '_activitypub_activity_type',
						'value' => 'Delete',
					),
				),
			)
		);

		// Get count of pending Delete activities.
		$pending_count = count( $pending_deletes );

		// If no more pending Delete activities, self-destruct is complete.
		if ( 0 === $pending_count ) {
			\WP_CLI::line( \WP_CLI::colorize( '%G✅ Status: COMPLETED%n' ) );
			\WP_CLI::line( \WP_CLI::colorize( '%GYour blog has been successfully removed from the Fediverse.%n' ) );
			\WP_CLI::line( '' );
			\WP_CLI::line( \WP_CLI::colorize( '%Y📋 What happened:%n' ) );
			\WP_CLI::line( \WP_CLI::colorize( '%Y• Delete activities were sent to all followers%n' ) );
			\WP_CLI::line( \WP_CLI::colorize( '%Y• Your blog is no longer discoverable on ActivityPub networks%n' ) );
			\WP_CLI::line( \WP_CLI::colorize( '%Y• The self-destruct process has finished%n' ) );
		} else {
			\WP_CLI::line( \WP_CLI::colorize( '%Y⏳ Status: IN PROGRESS%n' ) );
			\WP_CLI::line( \WP_CLI::colorize( '%YThe self-destruct process is currently running.%n' ) );
			\WP_CLI::line( '' );

			\WP_CLI::line( \WP_CLI::colorize( "%YProgress: {$pending_count} Delete Activities still pending%n" ) );

			\WP_CLI::line( '' );
			\WP_CLI::line( \WP_CLI::colorize( '%YNote: The process may take several minutes to complete.%n' ) );
		}

		\WP_CLI::line( '' );
	}
}
