<?php

namespace SugarCalendarBookings\Migration\Commands;

use SugarCalendarBookings\Migration\MigrationRegistry;
use SugarCalendarBookings\Migration\MigrationReport;
use SugarCalendarBookings\Migration\MigrationService;
use SugarCalendarBookings\Plugin;
use WP_CLI;

// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

/**
 * Migrate Command.
 *
 * WP CLI command for migrating data from external booking plugins.
 *
 * @since 1.3.0
 */
class MigrateCommand {

	/**
	 * Migration service.
	 *
	 * @since 1.3.0
	 *
	 * @var MigrationService
	 */
	private MigrationService $service;

	/**
	 * Migration registry.
	 *
	 * @since 1.3.0
	 *
	 * @var MigrationRegistry
	 */
	private MigrationRegistry $registry;

	/**
	 * Constructor.
	 *
	 * @since 1.3.0
	 */
	public function __construct() {

		$this->service  = Plugin::get( MigrationService::class );
		$this->registry = Plugin::get( MigrationRegistry::class );
	}

	/**
	 * Migrate data from external booking plugins to Sugar Calendar Bookings.
	 *
	 * ## OPTIONS
	 *
	 * [--source=<source>]
	 * : The source plugin to migrate from.
	 * ---
	 * default: amelia
	 * options:
	 *   - amelia
	 * ---
	 *
	 * [--entity=<entity>]
	 * : Entity type to migrate. Use 'all' to migrate all entities in dependency order.
	 * ---
	 * default: all
	 * options:
	 *   - all
	 *   - location
	 *   - customer
	 *   - employee
	 *   - service
	 *   - appointment
	 * ---
	 *
	 * [--dry-run]
	 * : Preview migration without making changes.
	 *
	 * [--batch-size=<batch-size>]
	 * : Number of records to process per batch.
	 * ---
	 * default: 50
	 * ---
	 *
	 * ## EXAMPLES
	 *
	 *     # Preview full migration from Amelia
	 *     wp scbookings migrate --source=amelia --dry-run
	 *
	 *     # Migrate all entities
	 *     wp scbookings migrate --source=amelia
	 *
	 *     # Migrate only customers
	 *     wp scbookings migrate --source=amelia --entity=customer
	 *
	 *     # Migrate with custom batch size
	 *     wp scbookings migrate --source=amelia --batch-size=100
	 *
	 * @since 1.3.0
	 *
	 * @param array<string>        $args       Positional arguments.
	 * @param array<string, mixed> $assoc_args Associative arguments.
	 */
	public function __invoke( $args, $assoc_args ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded

		$source_id   = $assoc_args['source'] ?? 'amelia';
		$entity_type = $assoc_args['entity'] ?? 'all';

		// Get adapter from registry.
		$adapter = $this->registry->get_adapter( $source_id );

		if ( ! $adapter ) {
			WP_CLI::error( sprintf( 'Unknown source: %s', $source_id ) );

			return;
		}

		// Validate source using service.
		$validation = $this->service->validate_source( $adapter );

		if ( is_wp_error( $validation ) ) {
			WP_CLI::error( $validation->get_error_message() );

			return;
		}

		// Validate entity type if specific entity requested.
		if ( $entity_type !== 'all' ) {
			$supported = $adapter->get_supported_entities();

			if ( ! in_array( $entity_type, $supported, true ) ) {
				WP_CLI::error( sprintf( 'Entity "%s" is not supported by %s.', $entity_type, $adapter->get_name() ) );

				return;
			}
		}

		// Build options for the service.
		$options = [
			'dry_run'    => isset( $assoc_args['dry-run'] ),
			'batch_size' => isset( $assoc_args['batch-size'] ) ? (int) $assoc_args['batch-size'] : MigrationService::DEFAULT_BATCH_SIZE,
			'entities'   => $entity_type !== 'all' ? [ $entity_type ] : [],
		];

		// Display settings.
		$this->display_settings( $adapter->get_name(), $entity_type, $options );

		// Confirm if not dry run.
		if ( ! $options['dry_run'] ) {
			WP_CLI::confirm( 'Are you sure you want to proceed with the migration?', $assoc_args );
		}

		WP_CLI::log( '' );
		WP_CLI::log( WP_CLI::colorize( '%B========================================%n' ) );
		WP_CLI::log( WP_CLI::colorize( '%B   Starting Migration Process          %n' ) );
		WP_CLI::log( WP_CLI::colorize( '%B========================================%n' ) );
		WP_CLI::log( '' );

		// Track overall start time.
		$overall_start = microtime( true );

		// Capture options for use in closures.
		$is_dry_run = $options['dry_run'];

		// Run full migration using service (handles issues tracking and metadata saving).
		$reports = $this->service->run_full_migration( // phpcs:ignore WPForms.Formatting.EmptyLineAfterAssigmentVariables.AddEmptyLine
			$adapter,
			$options,
			// Callback for entity start.
			function ( $entity, $step, $total ) {
				WP_CLI::log( WP_CLI::colorize( sprintf( '%%C--- Step %d/%d: Migrating %s ---%%n', $step, $total, ucfirst( $entity ) ) ) );
				WP_CLI::log( '' );
			},
			// Callback for batch complete (optional progress reporting).
			null,
			// Callback for entity complete - display summary immediately.
			function ( $entity, $report ) use ( $is_dry_run ) {
				$this->display_entity_summary( $report );

				if ( $report->has_errors() && ! $is_dry_run ) {
					WP_CLI::warning( sprintf( '%s migration completed with errors.', ucfirst( $entity ) ) );
				}

				WP_CLI::log( '' );
			}
		);

		// Calculate overall duration.
		$overall_duration = microtime( true ) - $overall_start;

		// Display final summary.
		$this->display_summary( $reports, $overall_duration, $options['dry_run'] );
	}

	/**
	 * Display migration settings.
	 *
	 * @since 1.3.0
	 *
	 * @param string               $source_name Source name.
	 * @param string               $entity_type Entity type.
	 * @param array<string, mixed> $options     Migration options.
	 */
	private function display_settings( string $source_name, string $entity_type, array $options ) {

		WP_CLI::log( '' );
		WP_CLI::log( WP_CLI::colorize( '%G=== Migration Settings ===%n' ) );
		WP_CLI::log( sprintf( 'Source: %s', $source_name ) );
		WP_CLI::log( sprintf( 'Entity: %s', $entity_type === 'all' ? 'All supported entities' : ucfirst( $entity_type ) ) );
		WP_CLI::log( sprintf( 'Mode: %s', $options['dry_run'] ? WP_CLI::colorize( '%YDry Run%n' ) : WP_CLI::colorize( '%GLive%n' ) ) );
		WP_CLI::log( sprintf( 'Batch Size: %d', $options['batch_size'] ) );
		WP_CLI::log( '' );
	}

	/**
	 * Display summary for a single entity migration.
	 *
	 * @since 1.3.0
	 *
	 * @param MigrationReport $report Migration report.
	 */
	private function display_entity_summary( MigrationReport $report ) {

		$data = $report->get_data();

		WP_CLI::log( sprintf( 'Total: %d', $data['total'] ) );
		WP_CLI::log( sprintf( 'Migrated: %s', WP_CLI::colorize( '%G' . $data['migrated'] . '%n' ) ) );
		WP_CLI::log( sprintf( 'Skipped: %s', WP_CLI::colorize( '%Y' . $data['skipped'] . '%n' ) ) );
		WP_CLI::log( sprintf( 'Failed: %s', WP_CLI::colorize( '%R' . $data['failed'] . '%n' ) ) );
		WP_CLI::log( sprintf( 'Duration: %.2f seconds', $data['duration'] ) );
	}

	/**
	 * Display final migration summary.
	 *
	 * @since 1.3.0
	 *
	 * @param array<string, MigrationReport> $reports          Entity migration reports.
	 * @param float                          $overall_duration Total duration in seconds.
	 * @param bool                           $is_dry_run       Whether this was a dry run.
	 */
	private function display_summary( array $reports, float $overall_duration, bool $is_dry_run ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh, Generic.Metrics.NestingLevel.MaxExceeded

		WP_CLI::log( '' );
		WP_CLI::log( WP_CLI::colorize( '%B========================================%n' ) );
		WP_CLI::log( WP_CLI::colorize( '%B   Migration Summary                   %n' ) );
		WP_CLI::log( WP_CLI::colorize( '%B========================================%n' ) );
		WP_CLI::log( '' );

		$total_migrated = 0;
		$total_skipped  = 0;
		$total_failed   = 0;
		$has_errors     = false;

		// Aggregate statistics and display breakdown.
		foreach ( $reports as $entity => $report ) {
			$data            = $report->get_data();
			$total_migrated += $data['migrated'];
			$total_skipped  += $data['skipped'];
			$total_failed   += $data['failed'];

			if ( $report->has_errors() ) {
				$has_errors = true;
			}

			WP_CLI::log( WP_CLI::colorize( '%G' . ucfirst( $entity ) . ':%n' ) );
			WP_CLI::log( sprintf( '  Migrated: %d', $data['migrated'] ) );
			WP_CLI::log( sprintf( '  Skipped: %d', $data['skipped'] ) );
			WP_CLI::log( sprintf( '  Failed: %d', $data['failed'] ) );
			WP_CLI::log( '' );
		}

		// Display totals.
		WP_CLI::log( WP_CLI::colorize( '%BTotals:%n' ) );
		WP_CLI::log( sprintf( 'Total Migrated: %s', WP_CLI::colorize( '%G' . $total_migrated . '%n' ) ) );
		WP_CLI::log( sprintf( 'Total Skipped: %s', WP_CLI::colorize( '%Y' . $total_skipped . '%n' ) ) );
		WP_CLI::log( sprintf( 'Total Failed: %s', WP_CLI::colorize( '%R' . $total_failed . '%n' ) ) );
		WP_CLI::log( sprintf( 'Overall Duration: %.2f seconds', $overall_duration ) );
		WP_CLI::log( '' );

		// Display errors if any.
		if ( $has_errors ) {
			WP_CLI::log( WP_CLI::colorize( '%R=== Errors ===%n' ) );

			foreach ( $reports as $entity => $report ) {
				if ( $report->has_errors() ) {
					$data = $report->get_data();

					WP_CLI::log( WP_CLI::colorize( '%R' . ucfirst( $entity ) . ':%n' ) );

					foreach ( $data['errors'] as $error ) {
						WP_CLI::warning( $error['message'] );
					}
				}
			}

			WP_CLI::log( '' );
		}

		// Final status.
		if ( $is_dry_run ) {
			WP_CLI::success( 'Dry run completed. No data was migrated.' );
		} elseif ( $has_errors || $total_failed > 0 ) {
			WP_CLI::error( 'Migration completed with errors.', false );
		} else {
			WP_CLI::success( 'Migration completed successfully!' );
		}
	}
}
