<?php
/**
 * `wp powersuite database` commands.
 *
 * @package WP_PowerSuite\CLI
 * @since 1.0.7
 */

namespace WP_PowerSuite\CLI;

use WP_PowerSuite\CLI\Support\Cli;

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

/**
 * Run WP PowerSuite Database Cleanup from the command line.
 *
 * Reuses the exact scanner/cleaner engine used by the admin module, including
 * its ownership-aware protections for templates, builder data, and active
 * plugin tables.
 *
 * @since 1.0.7
 */
final class DatabaseCommand {

	/**
	 * Scan for and optionally remove cleanable database items.
	 *
	 * Runs safe tasks by default. Caution-level tasks are only included with
	 * --include-caution. Destructive runs require confirmation (or --yes).
	 *
	 * ## OPTIONS
	 *
	 * [--dry-run]
	 * : Only report what would be removed; make no changes.
	 *
	 * [--include-caution]
	 * : Also run caution-level tasks (more aggressive). Still safe-listed by the
	 *   module's ownership rules.
	 *
	 * [--yes]
	 * : Skip the confirmation prompt for a destructive run.
	 *
	 * [--format=<format>]
	 * : Render the per-task report in a particular format.
	 * ---
	 * default: table
	 * options:
	 *   - table
	 *   - csv
	 *   - json
	 *   - yaml
	 * ---
	 *
	 * ## EXAMPLES
	 *
	 *     # See what would be cleaned
	 *     $ wp powersuite database cleanup --dry-run
	 *
	 *     # Clean safe items, no prompt
	 *     $ wp powersuite database cleanup --yes
	 *
	 * @when after_wp_load
	 *
	 * @param array<int, string>   $args       Positional arguments (unused).
	 * @param array<string, mixed> $assoc_args Associative arguments.
	 * @return void
	 */
	public function cleanup( array $args, array $assoc_args ): void {
		if ( ! Cli::isEnabled( 'database-cleanup' ) ) {
			\WP_CLI::error( __( 'The Database Cleanup module is not enabled. Enable it first: wp powersuite module enable database-cleanup', 'wp-powersuite' ) );
		}

		$this->ensureModuleLoaded();

		$settings = \DatabaseCleanup\Module::getStoredSettings();
		$scanner  = new \DatabaseCleanup\Includes\Database_Scanner();
		$scan     = $scanner->scan( $settings, true );

		$tasks = isset( $scan['tasks'] ) && is_array( $scan['tasks'] ) ? $scan['tasks'] : [];
		$rows  = [];
		foreach ( $tasks as $task_id => $task ) {
			$count = (int) ( $task['count'] ?? 0 );
			if ( $count <= 0 ) {
				continue;
			}
			$rows[] = [
				'task'    => (string) $task_id,
				'label'   => (string) ( $task['label'] ?? $task_id ),
				'items'   => $count,
				'size'    => size_format( (int) ( $task['estimated_bytes'] ?? 0 ) ),
				'safety'  => (string) ( $task['safety_level'] ?? ( ! empty( $task['safe'] ) ? 'safe' : 'caution' ) ),
			];
		}

		if ( $rows === [] ) {
			\WP_CLI::success( __( 'Nothing to clean up. The database is already tidy.', 'wp-powersuite' ) );
			return;
		}

		$format = Cli::format( $assoc_args, [ 'table', 'csv', 'json', 'yaml' ], 'table' );
		\WP_CLI\Utils\format_items( $format, $rows, [ 'task', 'label', 'items', 'size', 'safety' ] );

		\WP_CLI::log(
			sprintf(
				/* translators: 1: total items, 2: human-readable size */
				__( 'Total: %1$d item(s), ~%2$s reclaimable.', 'wp-powersuite' ),
				(int) ( $scan['total_count'] ?? 0 ),
				size_format( (int) ( $scan['total_bytes'] ?? 0 ) )
			)
		);

		if ( (bool) \WP_CLI\Utils\get_flag_value( $assoc_args, 'dry-run', false ) ) {
			\WP_CLI::success( __( 'Dry run complete. No changes were made.', 'wp-powersuite' ) );
			return;
		}

		$include_caution = (bool) \WP_CLI\Utils\get_flag_value( $assoc_args, 'include-caution', false );

		$task_ids = [];
		foreach ( $tasks as $task_id => $task ) {
			if ( (int) ( $task['count'] ?? 0 ) <= 0 ) {
				continue;
			}
			$is_safe = ! empty( $task['safe'] ) || (string) ( $task['safety_level'] ?? '' ) === 'safe';
			if ( ! $is_safe && ! $include_caution ) {
				continue;
			}
			$task_ids[] = (string) $task_id;
		}

		if ( $task_ids === [] ) {
			\WP_CLI::warning( __( 'Only caution-level items were found. Re-run with --include-caution to remove them.', 'wp-powersuite' ) );
			return;
		}

		\WP_CLI::confirm( __( 'This will permanently delete the items listed above. Continue?', 'wp-powersuite' ), $assoc_args );

		$cleaner = new \DatabaseCleanup\Includes\Database_Cleaner();
		$job_id  = $cleaner->create_job( $task_ids, $settings, false, $include_caution );

		if ( $job_id === '' ) {
			\WP_CLI::error( __( 'Could not start a cleanup job (another job may be running, or no eligible tasks).', 'wp-powersuite' ) );
		}

		$deleted   = 0;
		$bytes     = 0;
		$max_steps = 10000; // Hard stop so a stuck cursor can never loop forever.
		$progress  = \WP_CLI\Utils\make_progress_bar( __( 'Cleaning', 'wp-powersuite' ), count( $task_ids ) );

		for ( $step = 0; $step < $max_steps; $step++ ) {
			$result = $cleaner->run_step( $job_id, $settings, null );

			if ( ! empty( $result['error'] ) ) {
				$progress->finish();
				\WP_CLI::error( (string) $result['error'] );
			}

			$job = isset( $result['job'] ) && is_array( $result['job'] ) ? $result['job'] : [];
			if ( isset( $job['totals'] ) && is_array( $job['totals'] ) ) {
				$deleted = (int) ( $job['totals']['deleted'] ?? $deleted );
				$bytes   = (int) ( $job['totals']['bytes'] ?? $bytes );
			}

			$progress->tick();

			if ( ! empty( $result['done'] ) ) {
				break;
			}
		}

		$progress->finish();

		\WP_CLI::success(
			sprintf(
				/* translators: 1: deleted item count, 2: human-readable size */
				__( 'Cleanup complete: removed %1$d item(s), reclaimed ~%2$s.', 'wp-powersuite' ),
				$deleted,
				size_format( $bytes )
			)
		);
	}

	/**
	 * Ensure the Database Cleanup module classes are loaded.
	 *
	 * @return void
	 */
	private function ensureModuleLoaded(): void {
		if ( class_exists( '\\DatabaseCleanup\\Includes\\Database_Scanner' ) ) {
			return;
		}

		$module_file = WP_POWERSUITE_MODULES_DIR . 'database-cleanup' . DIRECTORY_SEPARATOR . 'module.php';
		if ( is_readable( $module_file ) ) {
			require_once $module_file;
		}

		if ( ! class_exists( '\\DatabaseCleanup\\Includes\\Database_Scanner' ) ) {
			\WP_CLI::error( __( 'Unable to load the Database Cleanup engine.', 'wp-powersuite' ) );
		}
	}
}
