<?php
/**
 * WP CLI Command for processing homepage redirects
 *
 * @link          https://aleksandrsamokhin.com
 * @since         1.0.0
 *
 * @author        Aleksandr Samokhin
 * @package       Redicl\CLI
 *
 * @copyright (c) 2025, Aleksandr Samokhin
 *
 * Usage:
 *   wp redirects process           - Process all redirects
 *   wp redirects process --limit=50 - Process only 50 URLs
 *   wp redirects process --offset=3000 - Start processing from position 3001
 *   wp redirects list              - List all homepage redirect URLs
 *   wp redirects count             - Count homepage redirect URLs
 *   wp redirects process --dry-run - Preview changes without updating
 */

namespace Redicl\CLI;

use Redicl\Core\Redirects_Helper;
use Redicl\Core\Redirects_Processor;

// Abort if called directly.
defined( 'WPINC' ) || die;

/**
 * WP CLI Command class for processing homepage redirects.
 */
class Fix_Redirects_CLI_Command {

	/**
	 * Get all source URLs that redirect to homepage.
	 *
	 * @param int $limit Limit the number of URLs to return.
	 * @return array Array of source URLs.
	 */
	private function get_homepage_redirect_urls( $limit = 0 ) {
		return Redirects_Processor::get_homepage_redirect_urls( $limit );
	}

	/**
	 * List all homepage redirect URLs
	 *
	 * ## OPTIONS
	 *
	 * [--limit=<number>]
	 * : Limit the number of URLs to display
	 * ---
	 * default: 0
	 * ---
	 *
	 * [--format=<format>]
	 * : Output format (table, csv, json)
	 * ---
	 * default: table
	 * options:
	 *   - table
	 *   - csv
	 *   - json
	 * ---
	 *
	 * ## EXAMPLES
	 *
	 *     wp redirects list
	 *     wp redirects list --limit=10
	 *     wp redirects list --format=csv
	 *
	 * @subcommand list
	 * @param array $args Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function list_urls( $args, $assoc_args ) {
		$limit  = isset( $assoc_args['limit'] ) ? intval( $assoc_args['limit'] ) : 0;
		$format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table';

		$urls = $this->get_homepage_redirect_urls( $limit );

		if ( empty( $urls ) ) {
			\WP_CLI::warning( __( 'No homepage redirects found.', 'redirect-cleanup' ) );
			return;
		}

		$items = array_map(
			function ( $url ) {
				return array( 'source_url' => '/' . $url );
			},
			$urls
		);

		\WP_CLI\Utils\format_items( $format, $items, array( 'source_url' ) );
		\WP_CLI::success(
			sprintf(
			// translators: %1$d is the number of homepage redirect URLs.
				__( 'Found %1$d homepage redirect URLs.', 'redirect-cleanup' ),
				count( $urls )
			)
		);
	}

	/**
	 * Count homepage redirect URLs
	 *
	 * ## EXAMPLES
	 *
	 *     wp redirects count
	 *
	 * @subcommand count
	 */
	public function count_urls() {
		$urls = $this->get_homepage_redirect_urls();
		\WP_CLI::success(
			sprintf(
			// translators: %1$d is the number of total homepage redirect URLs.
				__( 'Total homepage redirect URLs: %1$d', 'redirect-cleanup' ),
				count( $urls )
			)
		);
	}

	/**
	 * Process redirects and remove internal links from posts
	 *
	 * ## OPTIONS
	 *
	 * [--offset=<number>]
	 * : Skip the first N redirect URLs (start processing from this position)
	 * ---
	 * default: 0
	 * ---
	 *
	 * [--limit=<number>]
	 * : Limit the number of redirect URLs to process (after offset)
	 * ---
	 * default: 0
	 * ---
	 *
	 * [--batch-size=<number>]
	 * : Number of URLs to process per batch
	 * ---
	 * default: 20
	 * ---
	 *
	 * [--dry-run]
	 * : Preview changes without actually updating posts
	 *
	 * [--verbose]
	 * : Show detailed output for each post
	 *
	 * ## EXAMPLES
	 *
	 *     wp redirects process
	 *     wp redirects process --limit=50
	 *     wp redirects process --offset=3000
	 *     wp redirects process --offset=3000 --limit=500
	 *     wp redirects process --dry-run
	 *     wp redirects process --batch-size=10 --verbose
	 *
	 * @subcommand process
	 * @param array $args Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function process( $args, $assoc_args ) {
		$offset  = isset( $assoc_args['offset'] ) ? intval( $assoc_args['offset'] ) : 0;
		$limit   = isset( $assoc_args['limit'] ) ? intval( $assoc_args['limit'] ) : 0;
		$dry_run = isset( $assoc_args['dry-run'] );
		$verbose = isset( $assoc_args['verbose'] );

		if ( $dry_run ) {
			\WP_CLI::warning( __( 'DRY RUN MODE - No changes will be made.', 'redirect-cleanup' ) );
		}

		// Get all redirect URLs using shared processor.
		$all_redirect_urls = Redirects_Processor::get_homepage_redirect_urls();
		$total_available   = count( $all_redirect_urls );

		if ( empty( $all_redirect_urls ) ) {
			\WP_CLI::warning( __( 'No homepage redirects found to process.', 'redirect-cleanup' ) );
			return;
		}

		// Apply offset.
		if ( $offset > 0 ) {
			$all_redirect_urls = array_slice( $all_redirect_urls, $offset );
			\WP_CLI::log(
				sprintf(
				// translators: %1$d is the number of URLs to skip, %2$d is the starting position.
					__( 'Skipping first %1$d URLs (starting from position %2$d).', 'redirect-cleanup' ),
					$offset,
					$offset + 1
				)
			);
		}

		// Apply limit after offset.
		if ( $limit > 0 ) {
			$redirect_urls = array_slice( $all_redirect_urls, 0, $limit );
		} else {
			$redirect_urls = $all_redirect_urls;
		}

		if ( empty( $redirect_urls ) ) {
			\WP_CLI::warning( __( 'No redirect URLs to process after applying offset.', 'redirect-cleanup' ) );
			return;
		}

		\WP_CLI::log(
			sprintf(
				// translators: %1$d is the total number of available URLs, %2$d is the number of URLs to process, %3$d is the offset, %4$s is the limit.
				__( 'Total available: %1$d | Processing: %2$d URLs (offset: %3$d, limit: %4$s)', 'redirect-cleanup' ),
				$total_available,
				count( $redirect_urls ),
				$offset,
				$limit > 0 ? $limit : 'all'
			)
		);
		\WP_CLI::log( '' );

		$total_urls_processed = count( $redirect_urls );
		$start_time           = microtime( true );

		// Get all posts and filter using shared processor.
		$all_posts = Redirects_Processor::get_all_posts();

		if ( empty( $all_posts ) ) {
			\WP_CLI::warning( __( 'No published posts found.', 'redirect-cleanup' ) );
			return;
		}

		// Filter posts containing redirect URLs.
		$matching_posts = Redirects_Processor::filter_posts_with_urls( $all_posts, $redirect_urls );

		if ( empty( $matching_posts ) ) {
			\WP_CLI::warning( __( 'No posts found containing any of the redirect URLs.', 'redirect-cleanup' ) );
			return;
		}

		\WP_CLI::log(
			sprintf(
			// translators: %1$d is the number of posts to check, %2$d is the number of redirect URLs, %3$d is the total number of posts.
				__( 'Found %1$d posts to check for %2$d redirect URLs (from %3$d total posts).', 'redirect-cleanup' ),
				count( $matching_posts ),
				count( $redirect_urls ),
				count( $all_posts )
			)
		);

		// Create progress bar for posts.
		$progress = \WP_CLI\Utils\make_progress_bar( __( 'Processing posts', 'redirect-cleanup' ), count( $matching_posts ) );

		// Process each post individually for verbose output and progress bar.
		$total_posts_checked = 0;
		$total_posts_updated = 0;
		$total_links_removed = 0;
		$total_posts_skipped = 0;

		foreach ( $matching_posts as $post ) {
			++$total_posts_checked;

			// Use shared processor for single post.
			$result = Redirects_Processor::process_single_post( $post, $redirect_urls, $dry_run );

			if ( $result['updated'] ) {
				++$total_posts_updated;
				$total_links_removed += $result['links_removed'];

				if ( $verbose ) {
					if ( $dry_run ) {
						\WP_CLI::log(
							sprintf(
								// translators: %1$d is the post ID, %2$s is the post title, %3$d is the number of links removed.
								__( '  [DRY RUN] Would update post %1$d: %2$s (%3$d links removed)', 'redirect-cleanup' ),
								$result['post_id'],
								$result['post_title'],
								$result['links_removed']
							)
						);
					} else {
						\WP_CLI::success(
							sprintf(
								// translators: %1$d is the post ID, %2$s is the post title, %3$d is the number of links removed.
								__( '  Updated post %1$d: %2$s (%3$d links removed)', 'redirect-cleanup' ),
								$result['post_id'],
								$result['post_title'],
								$result['links_removed']
							)
						);
					}
				}

				if ( $result['error'] ) {
					\WP_CLI::warning(
						sprintf(
						// translators: %1$d is the post ID, %2$s is the error message.
							__( '  Failed to update post %1$d: %2$s', 'redirect-cleanup' ),
							$result['post_id'],
							$result['error']
						)
					);
				}
			} else {
				++$total_posts_skipped;
			}

			$progress->tick();
		}

		$progress->finish();

		$total_time = microtime( true ) - $start_time;

		// Output summary.
		\WP_CLI::log( '' );
		\WP_CLI::log( __( '=== SUMMARY ===', 'redirect-cleanup' ) );
		\WP_CLI::log(
			sprintf(
			// translators: %1$d is the offset, %2$s is the limit.
				__( 'Offset: %1$d | Limit: %2$s', 'redirect-cleanup' ),
				$offset,
				$limit > 0 ? $limit : 'none'
			)
		);
		\WP_CLI::log(
			sprintf(
				// translators: %1$d is the number of redirect URLs processed, %2$d is the starting position, %3$d is the ending position.
				__( 'Redirect URLs processed: %1$d (positions %2$d to %3$d)', 'redirect-cleanup' ),
				$total_urls_processed,
				$offset + 1,
				$offset + $total_urls_processed
			)
		);
		\WP_CLI::log(
			sprintf(
			// translators: %1$d is the number of posts checked.
				__( 'Posts checked: %1$d', 'redirect-cleanup' ),
				$total_posts_checked
			)
		);
		\WP_CLI::log(
			sprintf(
			// translators: %1$s is the action, %2$d is the number of posts updated.
				__( 'Posts %1$s: %2$d', 'redirect-cleanup' ),
				$dry_run ? __( 'would be updated', 'redirect-cleanup' ) : __( 'updated', 'redirect-cleanup' ),
				$total_posts_updated
			)
		);
		\WP_CLI::log(
			sprintf(
			// translators: %1$s is the action, %2$d is the number of links removed.
				__( 'Links %1$s: %2$d', 'redirect-cleanup' ),
				$dry_run ? __( 'would be removed', 'redirect-cleanup' ) : __( 'removed', 'redirect-cleanup' ),
				$total_links_removed
			)
		);
		\WP_CLI::log(
			sprintf(
			// translators: %1$d is the number of posts skipped.
				__( 'Posts skipped (no changes): %1$d', 'redirect-cleanup' ),
				$total_posts_skipped
			)
		);
		\WP_CLI::log(
			sprintf(
			// translators: %.2f is the total time in seconds, rounded to 2 decimal places.
				__( 'Total time: %.2f seconds', 'redirect-cleanup' ),
				$total_time
			)
		);

		if ( $dry_run ) {
			\WP_CLI::warning( __( 'This was a dry run. Run without --dry-run to apply changes.', 'redirect-cleanup' ) );
		} else {
			\WP_CLI::success( __( 'Processing complete!', 'redirect-cleanup' ) );
		}
	}

	/**
	 * Delete all homepage redirects from Yoast SEO Premium
	 *
	 * ## OPTIONS
	 *
	 * [--dry-run]
	 * : Preview which redirects would be deleted without actually deleting
	 *
	 * [--yes]
	 * : Skip confirmation prompt
	 *
	 * ## EXAMPLES
	 *
	 *     wp redirects delete-homepage-redirects
	 *     wp redirects delete-homepage-redirects --dry-run
	 *     wp redirects delete-homepage-redirects --yes
	 *
	 * @subcommand delete-homepage-redirects
	 * @param array $args Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function delete_homepage_redirects( $args, $assoc_args ) {
		$dry_run = isset( $assoc_args['dry-run'] );

		$redirects = Redirects_Helper::get_redirects( array() );

		if ( empty( $redirects ) ) {
			\WP_CLI::warning( __( 'No redirects found.', 'redirect-cleanup' ) );
			return;
		}

		$homepage_redirects = Redirects_Helper::get_homepage_redirects( $redirects );
		$to_delete          = array_keys( $homepage_redirects );

		if ( empty( $to_delete ) ) {
			\WP_CLI::warning( __( 'No homepage redirects found to delete.', 'redirect-cleanup' ) );
			return;
		}

		\WP_CLI::log(
			sprintf(
			// translators: %1$d is the number of homepage redirects to delete.
				__( 'Found %1$d homepage redirects to delete.', 'redirect-cleanup' ),
				count( $to_delete )
			)
		);

		if ( $dry_run ) {
			\WP_CLI::warning( __( 'DRY RUN MODE - No changes will be made.', 'redirect-cleanup' ) );
			foreach ( $to_delete as $url ) {
				\WP_CLI::log(
					sprintf(
					// translators: %1$s is the URL to delete.
						__( '  Would delete: /%1$s', 'redirect-cleanup' ),
						$url
					)
				);
			}
			return;
		}

		// Confirm deletion
		if ( ! isset( $assoc_args['yes'] ) ) {
			\WP_CLI::confirm(
				sprintf(
				// translators: %1$d is the number of homepage redirects to delete.
					__( 'Are you sure you want to delete %1$d homepage redirects?', 'redirect-cleanup' ),
					count( $to_delete )
				)
			);
		}

		// Remove the redirects
		foreach ( $to_delete as $url ) {
			unset( $redirects[ $url ] );
		}

		// Save updated redirects
		$updated = Redirects_Helper::update_redirects( $redirects );

		if ( $updated ) {
			\WP_CLI::success(
				sprintf(
				// translators: %1$d is the number of homepage redirects deleted.
					__( 'Deleted %1$d homepage redirects.', 'redirect-cleanup' ),
					count( $to_delete )
				)
			);
		} else {
			\WP_CLI::error( __( 'Failed to update redirects option.', 'redirect-cleanup' ) );
		}
	}
}
