/**
 * @description Master orchestrator for CloudCraze to Lightning migration
 * Manages migration phases, dependency resolution, and pre/post-flight checks
 * Supports resumable migrations with phase-based recovery
 * @author Senior Developer, NULogic
 * @version 1.0
 */
public class MigrationOrchestrator {

    public enum MigrationPhase {
        VALIDATION, PRODUCTS, PRICING, ORDERS, POST_MIGRATION
    }

    private List<MigrationPhase> migrationSequence;
    private Map<MigrationPhase, Id> phaseBatchJobs = new Map<MigrationPhase, Id>();
    private Map<MigrationPhase, Integer> phaseRecordCounts = new Map<MigrationPhase, Integer>();
    private Migration_Tracker__c tracker;
    private Boolean dryRunMode = false;

    public MigrationOrchestrator() {
        initializeMigrationSequence();
    }

    /**
     * Initialize the migration sequence with proper dependencies
     * Products must be migrated before Orders
     * Pricing must be migrated before Orders
     */
    private void initializeMigrationSequence() {
        migrationSequence = new List<MigrationPhase>{
            MigrationPhase.VALIDATION,
            MigrationPhase.PRODUCTS,
            MigrationPhase.PRICING,
            MigrationPhase.ORDERS,
            MigrationPhase.POST_MIGRATION
        };
    }

    /**
     * Start the migration process
     * @param phases List of phases to execute (allows partial execution)
     * @param isDryRun If true, validates but doesn't execute
     */
    public void startMigration(List<MigrationPhase> phases, Boolean isDryRun) {
        dryRunMode = isDryRun;

        try {
            createOrGetTracker();

            for (MigrationPhase phase : phases) {
                executePhase(phase);

                if (!dryRunMode) {
                    updateTrackerPhase(phase);
                }
            }

            logMigrationCompletion();
        } catch (Exception e) {
            handleMigrationError(e);
        }
    }

    /**
     * Execute a single migration phase
     */
    private void executePhase(MigrationPhase phase) {
        System.debug('Executing migration phase: ' + phase);

        switch on phase {
            when VALIDATION {
                executeValidationPhase();
            }
            when PRODUCTS {
                executeProductMigration();
            }
            when PRICING {
                executePricingMigration();
            }
            when ORDERS {
                executeOrderMigration();
            }
            when POST_MIGRATION {
                executePostMigration();
            }
        }
    }

    /**
     * Execute pre-flight validation phase
     * Checks data quality and governor limits
     */
    private void executeValidationPhase() {
        System.debug('Starting validation phase');

        // Check source data quality
        validateSourceData();

        // Verify governor limits
        checkGovernorLimits();

        // Verify target org readiness
        validateTargetOrgState();

        logPhaseResult(MigrationPhase.VALIDATION, 'Validation checks passed');
    }

    /**
     * Validate CloudCraze data quality
     */
    private void validateSourceData() {
        // Check for required fields
        List<ccrz__E_Product__c> productsWithoutCode = [
            SELECT Id FROM ccrz__E_Product__c
            WHERE ccrz__ProductCode__c = null
            LIMIT 1
        ];

        if (!productsWithoutCode.isEmpty()) {
            throw new MigrationException('Found products without ProductCode. Please clean data before migration.');
        }

        // Check for orphan order items
        List<ccrz__E_OrderItem__c> orphanItems = [
            SELECT Id FROM ccrz__E_OrderItem__c
            WHERE ccrz__Order__c = null
            LIMIT 1
        ];

        if (!orphanItems.isEmpty()) {
            throw new MigrationException('Found orphan order items without parent order.');
        }

        // Count records to migrate
        List<AggregateResult> counts = [
            SELECT COUNT() cnt FROM ccrz__E_Product__c WHERE ccrz__IsActive__c = true
        ];

        if (!counts.isEmpty() && (Integer)counts[0].get('cnt') == 0) {
            System.debug('Warning: No active products found to migrate');
        }
    }

    /**
     * Check Salesforce governor limits are sufficient
     */
    private void checkGovernorLimits() {
        Integer currentRequests = Limits.getDmlStatements();
        Integer remainingRequests = Limits.getLimitDmlStatements() - currentRequests;

        if (remainingRequests < 100) {
            throw new MigrationException('Insufficient DML statements remaining: ' + remainingRequests);
        }

        Integer heapUsed = Limits.getHeapSize();
        Integer heapMax = Limits.getLimitHeapSize();
        Integer heapPercent = (heapUsed * 100) / heapMax;

        if (heapPercent > 80) {
            throw new MigrationException('Heap memory usage too high: ' + heapPercent + '%');
        }

        System.debug('Governor limits check passed. Heap: ' + heapPercent + '% | DML: ' + remainingRequests);
    }

    /**
     * Validate target org readiness for migration
     */
    private void validateTargetOrgState() {
        // Verify Standard Pricebook exists
        List<Pricebook2> stdPricebooks = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
        if (stdPricebooks.isEmpty()) {
            throw new MigrationException('Standard Pricebook not found in target org.');
        }

        // Check for duplicate Product codes that might conflict
        List<AggregateResult> duplicates = [
            SELECT COUNT() cnt, ProductCode FROM Product2
            GROUP BY ProductCode HAVING COUNT() > 1
            LIMIT 1
        ];

        if (!duplicates.isEmpty()) {
            System.debug('Warning: Found duplicate product codes in target org');
        }
    }

    /**
     * Execute product migration
     */
    private void executeProductMigration() {
        System.debug('Starting product migration');

        if (dryRunMode) {
            Integer productCount = [SELECT COUNT() FROM ccrz__E_Product__c WHERE ccrz__IsActive__c = true];
            logPhaseResult(MigrationPhase.PRODUCTS, 'DRY RUN: Would migrate ' + productCount + ' products');
            return;
        }

        // Schedule batch job
        CCRZProductMigrationBatch batch = new CCRZProductMigrationBatch();
        Id jobId = Database.executeBatch(batch, 200);

        phaseBatchJobs.put(MigrationPhase.PRODUCTS, jobId);
        logPhaseResult(MigrationPhase.PRODUCTS, 'Batch job scheduled: ' + jobId);
    }

    /**
     * Execute pricing migration
     */
    private void executePricingMigration() {
        System.debug('Starting pricing migration');

        if (dryRunMode) {
            Integer pricelistCount = [SELECT COUNT() FROM ccrz__E_PriceList__c WHERE ccrz__IsActive__c = true];
            logPhaseResult(MigrationPhase.PRICING, 'DRY RUN: Would migrate ' + pricelistCount + ' pricelists');
            return;
        }

        // Verify products were migrated first
        Integer productCount = [SELECT COUNT() FROM Product2 WHERE CreatedDate = TODAY];
        if (productCount == 0) {
            throw new MigrationException('No products found. Execute PRODUCTS phase first.');
        }

        // Schedule pricing batch
        CCRZPricingMigrationBatch batch = new CCRZPricingMigrationBatch();
        Id jobId = Database.executeBatch(batch, 100);

        phaseBatchJobs.put(MigrationPhase.PRICING, jobId);
        logPhaseResult(MigrationPhase.PRICING, 'Batch job scheduled: ' + jobId);
    }

    /**
     * Execute order migration
     */
    private void executeOrderMigration() {
        System.debug('Starting order migration');

        if (dryRunMode) {
            Integer orderCount = [SELECT COUNT() FROM ccrz__E_Order__c];
            logPhaseResult(MigrationPhase.ORDERS, 'DRY RUN: Would migrate ' + orderCount + ' orders');
            return;
        }

        // Verify dependencies
        Integer productCount = [SELECT COUNT() FROM Product2 WHERE CreatedDate = TODAY];
        Integer pricebookCount = [SELECT COUNT() FROM Pricebook2 WHERE CreatedDate = TODAY];

        if (productCount == 0 || pricebookCount == 0) {
            throw new MigrationException('Products and Pricing must be migrated before Orders.');
        }

        // Schedule order batch
        CCRZOrderHistoryMigration batch = new CCRZOrderHistoryMigration();
        Id jobId = Database.executeBatch(batch, 200);

        phaseBatchJobs.put(MigrationPhase.ORDERS, jobId);
        logPhaseResult(MigrationPhase.ORDERS, 'Batch job scheduled: ' + jobId);
    }

    /**
     * Execute post-migration tasks
     * Runs reconciliation and validation
     */
    private void executePostMigration() {
        System.debug('Starting post-migration validation');

        DataReconciliationEngine reconciliation = new DataReconciliationEngine();
        Map<String, ReconciliationResult> results = reconciliation.runFullReconciliation();

        Boolean allPassed = true;
        for (String objectName : results.keySet()) {
            ReconciliationResult result = results.get(objectName);
            if (!result.passed) {
                allPassed = false;
                System.debug('Reconciliation failed for ' + objectName + ': ' + result.message);
            }
        }

        logPhaseResult(MigrationPhase.POST_MIGRATION,
            allPassed ? 'Post-migration validation: PASSED' : 'Post-migration validation: ISSUES FOUND');
    }

    /**
     * Create or retrieve existing migration tracker
     */
    private void createOrGetTracker() {
        List<Migration_Tracker__c> existing = [
            SELECT Id, Last_Completed_Phase__c FROM Migration_Tracker__c
            WHERE Status__c = 'In Progress'
            ORDER BY CreatedDate DESC
            LIMIT 1
        ];

        if (!existing.isEmpty()) {
            tracker = existing[0];
        } else {
            tracker = new Migration_Tracker__c();
            tracker.Status__c = 'In Progress';
            tracker.Started_Date__c = System.now();
            insert tracker;
        }
    }

    /**
     * Update tracker with completed phase
     */
    private void updateTrackerPhase(MigrationPhase phase) {
        tracker.Last_Completed_Phase__c = String.valueOf(phase);
        tracker.Last_Phase_Completion__c = System.now();
        update tracker;
    }

    /**
     * Log phase result to audit trail
     */
    private void logPhaseResult(MigrationPhase phase, String message) {
        Migration_Log__c log = new Migration_Log__c();
        log.Object_Type__c = 'Migration_Orchestration';
        log.Migration_Phase__c = String.valueOf(phase);
        log.Error_Message__c = message;
        log.Status__c = 'Info';
        insert log;
    }

    /**
     * Log migration completion
     */
    private void logMigrationCompletion() {
        tracker.Status__c = 'Completed';
        tracker.Completed_Date__c = System.now();
        update tracker;

        sendCompletionEmail();
    }

    /**
     * Handle migration errors with cleanup
     */
    private void handleMigrationError(Exception e) {
        System.debug('Migration failed: ' + e.getMessage());

        tracker.Status__c = 'Failed';
        tracker.Error_Message__c = e.getMessage();
        update tracker;

        Migration_Log__c errorLog = new Migration_Log__c();
        errorLog.Object_Type__c = 'Migration_Orchestration';
        errorLog.Migration_Phase__c = 'FATAL_ERROR';
        errorLog.Error_Message__c = e.getMessage();
        errorLog.Status__c = 'Error';
        insert errorLog;
    }

    /**
     * Send completion email to admin
     */
    private void sendCompletionEmail() {
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(new String[]{'migration-admin@nulogic.com'});
        mail.setSubject('CloudCraze Migration Orchestration Complete');

        String body = 'Migration orchestration completed.\n\n' +
                     'Tracker ID: ' + tracker.Id + '\n' +
                     'Status: ' + tracker.Status__c + '\n' +
                     'Started: ' + tracker.Started_Date__c.format() + '\n' +
                     'Completed: ' + tracker.Completed_Date__c.format();

        mail.setPlainTextBody(body);

        try {
            Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
        } catch (Exception e) {
            System.debug('Email delivery failed: ' + e.getMessage());
        }
    }

    /**
     * Resume migration from last completed phase
     */
    public void resumeMigration() {
        createOrGetTracker();

        String lastPhase = tracker.Last_Completed_Phase__c;
        List<MigrationPhase> remainingPhases = new List<MigrationPhase>();

        Boolean includeRemaining = false;
        for (MigrationPhase phase : migrationSequence) {
            if (phase.name() == lastPhase) {
                includeRemaining = true;
                continue;
            }
            if (includeRemaining) {
                remainingPhases.add(phase);
            }
        }

        if (!remainingPhases.isEmpty()) {
            startMigration(remainingPhases, false);
        }
    }

    /**
     * Rollback migration with audit trail
     */
    public void rollbackMigration(MigrationPhase phase) {
        MigrationRollbackService rollback = new MigrationRollbackService();
        rollback.rollbackPhase(phase);

        tracker.Status__c = 'Rolled Back';
        tracker.Rollback_Date__c = System.now();
        update tracker;
    }

    /**
     * Custom exception for orchestration errors
     */
    public class MigrationException extends Exception {}

    /**
     * Result wrapper for reconciliation
     */
    public class ReconciliationResult {
        public Boolean passed;
        public String message;
        public Integer sourceCount;
        public Integer targetCount;
    }
}
