<?php

declare(strict_types=1);

namespace CloudXM\NFe\CLI;

use CloudXM\NFe\Services\ApiClient;
use CloudXM\NFe\Persistence\NfeEmissionsRepository;
use CloudXM\SDK\Support\HasLogger;
use WP_CLI;

/**
 * WP-CLI Command for migrating NFe data to v2 schema
 * 
 * Usage: wp nfe migrate-to-v2 [--batch-size=100] [--dry-run]
 */
class MigrateToV2Command
{
    use HasLogger;

    private const BATCH_SIZE = 100;

    public function __construct(
        private ApiClient $apiClient,
        private NfeEmissionsRepository $emissionRepo
    ) {}

    /**
     * Migrate NFe emissions to v2 schema
     * 
     * ## OPTIONS
     * 
     * [--batch-size=<size>]
     * : Number of records to process per batch (default: 100)
     * 
     * [--dry-run]
     * : Run without making changes
     * 
     * [--resume-from=<id>]
     * : Resume from specific emission ID
     * 
     * ## EXAMPLES
     * 
     *     wp nfe migrate-to-v2
     *     wp nfe migrate-to-v2 --batch-size=50
     *     wp nfe migrate-to-v2 --dry-run
     *     wp nfe migrate-to-v2 --resume-from=1000
     * 
     * @param array $args
     * @param array $assoc_args
     */
    public function __invoke(array $args, array $assoc_args): void
    {
        $batchSize = (int) ($assoc_args['batch-size'] ?? self::BATCH_SIZE);
        $dryRun = isset($assoc_args['dry-run']);
        $resumeFrom = (int) ($assoc_args['resume-from'] ?? 0);

        WP_CLI::line('');
        WP_CLI::line('NFe API v2 Migration');
        WP_CLI::line('====================');
        WP_CLI::line('');
        WP_CLI::line(sprintf('Batch size: %d', $batchSize));
        WP_CLI::line(sprintf('Dry run: %s', $dryRun ? 'Yes' : 'No'));
        if ($resumeFrom > 0) {
            WP_CLI::line(sprintf('Resuming from ID: %d', $resumeFrom));
        }
        WP_CLI::line('');

        // Create backup
        if (!$dryRun) {
            WP_CLI::line('Creating database backup...');
            $this->createBackup();
            WP_CLI::success('Backup created');
        }

        // Get total count
        $total = $this->emissionRepo->count();
        WP_CLI::line(sprintf('Total emissions to migrate: %d', $total));
        WP_CLI::line('');

        $processed = 0;
        $updated = 0;
        $failed = 0;
        $skipped = 0;
        $errors = [];

        $offset = $resumeFrom;

        while ($offset < $total) {
            $emissions = $this->emissionRepo->findAll($batchSize, $offset);

            if (empty($emissions)) {
                break;
            }

            foreach ($emissions as $emission) {
                $processed++;

                // Skip if already has v2 fields
                if (!empty($emission['processing_strategy'])) {
                    $skipped++;
                    continue;
                }

                try {
                    // Fetch current invoice data from v2 API
                    $invoice = $this->apiClient->getInvoiceV2($emission['invoice_id']);

                    if (!$dryRun) {
                        // Update with v2 fields
                        $this->emissionRepo->update($emission['id'], [
                            'processing_strategy' => $invoice->processing_strategy,
                            'allowed_actions' => json_encode($invoice->allowed_actions),
                            'created_at' => $invoice->lifecycle?->created_at,
                            'issued_at' => $invoice->lifecycle?->issued_at ?? $emission['issued_at'],
                            'cancelled_at' => $invoice->lifecycle?->cancelled_at,
                        ]);

                        // Migrate legacy service_code if present
                        $this->migrateLegacyServiceCode($emission['order_id']);
                    }

                    $updated++;

                    // Log progress every 100 records
                    if ($processed % 100 === 0) {
                        $this->log()->info('nfe.migration.progress', [
                            'processed' => $processed,
                            'updated' => $updated,
                            'failed' => $failed,
                            'skipped' => $skipped
                        ]);

                        WP_CLI::line(sprintf(
                            'Progress: %d/%d (Updated: %d, Failed: %d, Skipped: %d)',
                            $processed,
                            $total,
                            $updated,
                            $failed,
                            $skipped
                        ));
                    }
                } catch (\Exception $e) {
                    $failed++;
                    $errors[] = [
                        'emission_id' => $emission['id'],
                        'invoice_id' => $emission['invoice_id'],
                        'error' => $e->getMessage()
                    ];

                    $this->log()->error('nfe.migration.failed', [
                        'emission_id' => $emission['id'],
                        'invoice_id' => $emission['invoice_id'],
                        'error' => $e->getMessage()
                    ]);
                }
            }

            $offset += $batchSize;

            // Small delay to avoid overwhelming the API
            if (!$dryRun) {
                usleep(100000); // 100ms
            }
        }

        // Final report
        WP_CLI::line('');
        WP_CLI::line('Migration Complete');
        WP_CLI::line('==================');
        WP_CLI::line(sprintf('Total processed: %d', $processed));
        WP_CLI::line(sprintf('Successfully updated: %d', $updated));
        WP_CLI::line(sprintf('Failed: %d', $failed));
        WP_CLI::line(sprintf('Skipped (already migrated): %d', $skipped));
        WP_CLI::line('');

        if (!empty($errors)) {
            WP_CLI::warning(sprintf('%d errors occurred during migration:', count($errors)));
            foreach (array_slice($errors, 0, 10) as $error) {
                WP_CLI::line(sprintf(
                    '  - Emission #%d (Invoice: %s): %s',
                    $error['emission_id'],
                    $error['invoice_id'],
                    $error['error']
                ));
            }
            if (count($errors) > 10) {
                WP_CLI::line(sprintf('  ... and %d more errors', count($errors) - 10));
            }
        }

        $this->log()->info('nfe.migration.completed', [
            'processed' => $processed,
            'updated' => $updated,
            'failed' => $failed,
            'skipped' => $skipped,
            'dry_run' => $dryRun
        ]);

        if ($failed > 0) {
            WP_CLI::error('Migration completed with errors');
        } else {
            WP_CLI::success('Migration completed successfully');
        }
    }

    /**
     * Create database backup
     */
    private function createBackup(): void
    {
        global $wpdb;

        $table = $wpdb->prefix . 'cloudxm_nfe_emissions';
        $backupTable = $table . '_backup_' . date('Y_m_d_His');

        $wpdb->query("CREATE TABLE {$backupTable} LIKE {$table}");
        $wpdb->query("INSERT INTO {$backupTable} SELECT * FROM {$table}");

        $this->log()->info('nfe.migration.backup_created', [
            'backup_table' => $backupTable
        ]);
    }

    /**
     * Migrate legacy service_code from order meta
     */
    private function migrateLegacyServiceCode(int $orderId): void
    {
        $order = wc_get_order($orderId);
        if (!$order) {
            return;
        }

        $legacyServiceCode = $order->get_meta('_cloudxm_nfe_service_code');
        if (empty($legacyServiceCode)) {
            return;
        }

        // Check if new fields already exist
        $municipalCode = $order->get_meta('_cloudxm_nfe_municipal_service_code');
        $nationalCode = $order->get_meta('_cloudxm_nfe_national_service_code');

        // Migrate to both new fields if they don't exist
        if (empty($municipalCode)) {
            $order->update_meta_data('_cloudxm_nfe_municipal_service_code', $legacyServiceCode);
        }

        if (empty($nationalCode)) {
            $order->update_meta_data('_cloudxm_nfe_national_service_code', $legacyServiceCode);
        }

        $order->save();

        $this->log()->info('nfe.migration.service_code_migrated', [
            'order_id' => $orderId,
            'legacy_service_code' => $legacyServiceCode
        ]);
    }
}
