/**
 * @description Comprehensive test suite for CloudCraze migration
 * Tests all batch classes, orchestrator, and data validation
 * @author Senior Developer, NULogic
 * @version 1.0
 */
@isTest
public class CCRZMigrationTestSuite {

    @TestSetup
    static void setupTestData() {
        // Create test account
        Account testAccount = new Account();
        testAccount.Name = 'Test Buyer Account';
        insert testAccount;

        // Create test products
        List<ccrz__E_Product__c> ccrzProducts = new List<ccrz__E_Product__c>();
        for (Integer i = 0; i < 10; i++) {
            ccrz__E_Product__c product = new ccrz__E_Product__c();
            product.ccrz__ProductCode__c = 'TEST-SKU-' + i;
            product.ccrz__ProductName__c = 'Test Product ' + i;
            product.ccrz__ProductDescription__c = 'Test Description ' + i;
            product.ccrz__ProductType__c = 'MERCHANDISE';
            product.ccrz__ProductFamily__c = 'Test Family';
            product.ccrz__IsActive__c = true;
            product.ccrz__Weight__c = 5.0;
            product.ccrz__WeightUnit__c = 'LB';
            ccrzProducts.add(product);
        }
        insert ccrzProducts;

        // Create test pricelist
        ccrz__E_PriceList__c pricelist = new ccrz__E_PriceList__c();
        pricelist.ccrz__PriceListCode__c = 'TEST-PRICELIST-001';
        pricelist.ccrz__PriceListName__c = 'Test Price List';
        pricelist.ccrz__CurrencyCode__c = 'USD';
        pricelist.ccrz__IsActive__c = true;
        insert pricelist;

        // Create test pricelist items
        List<ccrz__E_PriceListItem__c> priceListItems = new List<ccrz__E_PriceListItem__c>();
        for (ccrz__E_Product__c product : ccrzProducts) {
            ccrz__E_PriceListItem__c item = new ccrz__E_PriceListItem__c();
            item.ccrz__PriceList__c = pricelist.Id;
            item.ccrz__Product__c = product.Id;
            item.ccrz__ListPrice__c = 99.99;
            item.ccrz__UnitPrice__c = 79.99;
            item.ccrz__DiscountPercent__c = 20;
            item.ccrz__VolumeTierStartQty__c = 1;
            item.ccrz__VolumeTierEndQty__c = 10;
            item.ccrz__IsActive__c = true;
            priceListItems.add(item);
        }
        insert priceListItems;

        // Create test orders
        List<ccrz__E_Order__c> orders = new List<ccrz__E_Order__c>();
        for (Integer i = 0; i < 5; i++) {
            ccrz__E_Order__c order = new ccrz__E_Order__c();
            order.ccrz__Account__c = testAccount.Id;
            order.ccrz__OrderNumber__c = 'ORDER-' + i;
            order.ccrz__OrderDate__c = System.today();
            order.ccrz__OrderStatus__c = 'SUBMITTED';
            order.ccrz__OrderTotal__c = 500.00;
            order.ccrz__OrderSubtotal__c = 450.00;
            order.ccrz__OrderTax__c = 40.00;
            order.ccrz__OrderShipping__c = 10.00;
            order.ccrz__ShippingMethod__c = 'Ground';
            order.ccrz__ShippingCity__c = 'Denver';
            order.ccrz__ShippingState__c = 'CO';
            order.ccrz__ShippingPostalCode__c = '80202';
            order.ccrz__ShippingCountry__c = 'USA';
            orders.add(order);
        }
        insert orders;

        // Create test order items
        List<ccrz__E_OrderItem__c> orderItems = new List<ccrz__E_OrderItem__c>();
        Integer productIndex = 0;
        for (ccrz__E_Order__c order : orders) {
            for (Integer j = 0; j < 2; j++) {
                ccrz__E_OrderItem__c item = new ccrz__E_OrderItem__c();
                item.ccrz__Order__c = order.Id;
                item.ccrz__Product__c = ccrzProducts[productIndex % ccrzProducts.size()].Id;
                item.ccrz__Quantity__c = 5;
                item.ccrz__UnitPrice__c = 79.99;
                item.ccrz__LineTotal__c = 399.95;
                item.ccrz__TaxAmount__c = 32.00;
                orderItems.add(item);
                productIndex++;
            }
        }
        insert orderItems;
    }

    @isTest
    static void testProductMigrationBatch() {
        Test.startTest();

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

        Test.stopTest();

        // Verify batch job was created
        System.assertNotEquals(null, jobId);

        // Verify products were created
        List<Product2> migratedProducts = [SELECT Id, ProductCode FROM Product2 WHERE CreatedDate = TODAY];
        System.assertEquals(10, migratedProducts.size(), 'Should have migrated 10 products');

        // Verify product codes match
        Set<String> expectedCodes = new Set<String>();
        for (Integer i = 0; i < 10; i++) {
            expectedCodes.add('TEST-SKU-' + i);
        }

        Set<String> actualCodes = new Set<String>();
        for (Product2 prod : migratedProducts) {
            actualCodes.add(prod.ProductCode);
        }

        System.assertEquals(expectedCodes, actualCodes, 'Product codes should match');
    }

    @isTest
    static void testPricingMigrationBatch() {
        Test.startTest();

        // First migrate products as dependency
        CCRZProductMigrationBatch productBatch = new CCRZProductMigrationBatch();
        Database.executeBatch(productBatch, 200);

        Test.stopTest();

        // Create pricebook for target
        Pricebook2 customPricebook = new Pricebook2();
        customPricebook.Name = 'Test Custom Pricebook';
        customPricebook.IsActive = true;
        insert customPricebook;

        Test.startTest();

        CCRZPricingMigrationBatch pricingBatch = new CCRZPricingMigrationBatch();
        Id jobId = Database.executeBatch(pricingBatch, 100);

        Test.stopTest();

        // Verify pricebook entries were created
        List<PricebookEntry> entries = [SELECT Id, UnitPrice FROM PricebookEntry WHERE CreatedDate = TODAY];
        System.assert(entries.size() > 0, 'Should have created pricebook entries');

        // Verify prices are set correctly
        for (PricebookEntry entry : entries) {
            System.assertNotEquals(null, entry.UnitPrice);
            System.assert(entry.UnitPrice > 0, 'Price should be positive');
        }
    }

    @isTest
    static void testOrderMigrationBatch() {
        Test.startTest();

        // Setup dependencies - products and pricing
        CCRZProductMigrationBatch productBatch = new CCRZProductMigrationBatch();
        Database.executeBatch(productBatch, 200);

        Test.stopTest();

        // Verify standard pricebook entries exist
        Pricebook2 standardPb = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
        List<Product2> products = [SELECT Id FROM Product2 WHERE CreatedDate = TODAY];

        List<PricebookEntry> entries = new List<PricebookEntry>();
        for (Product2 prod : products) {
            PricebookEntry entry = new PricebookEntry();
            entry.Product2Id = prod.Id;
            entry.Pricebook2Id = standardPb.Id;
            entry.UnitPrice = 99.99;
            entry.IsActive = true;
            entries.add(entry);
        }
        insert entries;

        Test.startTest();

        CCRZOrderHistoryMigration orderBatch = new CCRZOrderHistoryMigration();
        Id jobId = Database.executeBatch(orderBatch, 200);

        Test.stopTest();

        // Verify orders were migrated
        List<Order> migratedOrders = [SELECT Id, AccountId, Amount FROM Order WHERE CreatedDate = TODAY];
        System.assertEquals(5, migratedOrders.size(), 'Should have migrated 5 orders');

        // Verify account relationships
        for (Order order : migratedOrders) {
            System.assertNotEquals(null, order.AccountId, 'Order should have AccountId');
            System.assertEquals(500, order.Amount, 'Order amount should match');
        }
    }

    @isTest
    static void testMigrationOrchestrator() {
        Test.startTest();

        MigrationOrchestrator orchestrator = new MigrationOrchestrator();
        List<MigrationOrchestrator.MigrationPhase> phases = new List<MigrationOrchestrator.MigrationPhase>{
            MigrationOrchestrator.MigrationPhase.VALIDATION,
            MigrationOrchestrator.MigrationPhase.PRODUCTS
        };

        orchestrator.startMigration(phases, false);

        Test.stopTest();

        // Verify tracker was created
        List<Migration_Tracker__c> trackers = [SELECT Id, Status__c FROM Migration_Tracker__c];
        System.assertEquals(true, trackers.size() > 0, 'Migration tracker should be created');
    }

    @isTest
    static void testDataReconciliation() {
        Test.startTest();

        // Create test products in target
        List<Product2> products = new List<Product2>();
        for (Integer i = 0; i < 5; i++) {
            Product2 prod = new Product2();
            prod.Name = 'Test Product ' + i;
            prod.ProductCode = 'TEST-SKU-' + i;
            prod.IsActive = true;
            products.add(prod);
        }
        insert products;

        Test.stopTest();

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

        System.assertNotEquals(null, results, 'Reconciliation results should not be null');
        System.assertEquals(true, results.containsKey('Product'), 'Should have Product results');
    }

    @isTest
    static void testRollbackService() {
        Test.startTest();

        // Create test product to rollback
        Product2 testProduct = new Product2();
        testProduct.Name = 'Rollback Test Product';
        testProduct.ProductCode = 'ROLLBACK-TEST';
        testProduct.IsActive = true;
        insert testProduct;

        Test.stopTest();

        MigrationRollbackService rollback = new MigrationRollbackService();
        Map<String, Integer> dryRunResults = rollback.rollbackDryRun(MigrationOrchestrator.MigrationPhase.PRODUCTS);

        System.assertNotEquals(null, dryRunResults);
        System.assertEquals(true, dryRunResults.containsKey('Product2'));
    }

    @isTest
    static void testErrorHandling() {
        Test.startTest();

        // Create product without required fields to test error handling
        ccrz__E_Product__c invalidProduct = new ccrz__E_Product__c();
        // Note: ProductCode is required - omitting it intentionally
        invalidProduct.ccrz__ProductName__c = 'Invalid Product';
        invalidProduct.ccrz__IsActive__c = true;

        try {
            insert invalidProduct;
            CCRZProductMigrationBatch batch = new CCRZProductMigrationBatch();
            Database.executeBatch(batch, 200);
        } catch (DmlException e) {
            System.assert(true, 'Error handling working as expected');
        }

        Test.stopTest();
    }

    @isTest
    static void testGovernorLimits() {
        Test.startTest();

        // Run migration to test governor limit checks
        MigrationOrchestrator orchestrator = new MigrationOrchestrator();
        List<MigrationOrchestrator.MigrationPhase> phases = new List<MigrationOrchestrator.MigrationPhase>{
            MigrationOrchestrator.MigrationPhase.VALIDATION
        };

        orchestrator.startMigration(phases, true); // Dry run mode

        Test.stopTest();

        // Verify governor limits are respected
        System.assert(Limits.getDmlStatements() <= Limits.getLimitDmlStatements());
        System.assert(Limits.getHeapSize() <= Limits.getLimitHeapSize());
    }

    @isTest
    static void testDuplicateSkuDetection() {
        Test.startTest();

        // Create duplicate SKU scenario
        List<ccrz__E_Product__c> products = [
            SELECT Id, ccrz__ProductCode__c FROM ccrz__E_Product__c LIMIT 1
        ];

        ccrz__E_Product__c duplicate = new ccrz__E_Product__c();
        duplicate.ccrz__ProductCode__c = products[0].ccrz__ProductCode__c;
        duplicate.ccrz__ProductName__c = 'Duplicate Product';
        duplicate.ccrz__IsActive__c = true;

        try {
            insert duplicate;
            CCRZProductMigrationBatch batch = new CCRZProductMigrationBatch();
            Database.executeBatch(batch, 200);
        } catch (Exception e) {
            System.assert(e.getMessage().contains('Duplicate'), 'Should detect duplicate SKU');
        }

        Test.stopTest();
    }

    @isTest
    static void testNullFieldHandling() {
        Test.startTest();

        // Create product with null description
        ccrz__E_Product__c nullDescProduct = new ccrz__E_Product__c();
        nullDescProduct.ccrz__ProductCode__c = 'NULL-DESC-TEST';
        nullDescProduct.ccrz__ProductName__c = 'Null Desc Product';
        nullDescProduct.ccrz__ProductDescription__c = null;
        nullDescProduct.ccrz__IsActive__c = true;
        insert nullDescProduct;

        CCRZProductMigrationBatch batch = new CCRZProductMigrationBatch();
        Database.executeBatch(batch, 200);

        Test.stopTest();

        List<Product2> migratedProducts = [
            SELECT Id, Description FROM Product2
            WHERE ProductCode = 'NULL-DESC-TEST'
        ];

        System.assertEquals(1, migratedProducts.size());
        System.assertNotEquals(null, migratedProducts[0].Description, 'Should have default description');
    }

    @isTest
    static void testOrderTotalValidation() {
        Test.startTest();

        Account testAccount = [SELECT Id FROM Account LIMIT 1];
        List<ccrz__E_Order__c> orders = [SELECT Id FROM ccrz__E_Order__c LIMIT 1];

        CCRZOrderHistoryMigration.validateOrderTotals();

        Test.stopTest();

        // Verify validation method executes without error
        System.assert(true, 'Order validation completed');
    }

    @isTest
    static void testMigrationLogging() {
        Test.startTest();

        CCRZProductMigrationBatch batch = new CCRZProductMigrationBatch();
        Database.executeBatch(batch, 200);

        Test.stopTest();

        // Verify logs were created
        List<Migration_Log__c> logs = [SELECT Id, Migration_Phase__c FROM Migration_Log__c];
        System.assert(logs.size() > 0, 'Migration logs should be created');
    }
}
