/**
 * @description Post-migration validation and reconciliation engine
 * Compares migrated data between source and target, validates relationships and data integrity
 * Generates comprehensive reconciliation reports
 * @author Senior Developer, NULogic
 * @version 1.0
 */
public class DataReconciliationEngine {

    private Map<String, ObjectReconciliation> reconciliationResults;
    private Reconciliation_Report__c reportRecord;
    private List<Reconciliation_Detail__c> detailRecords;

    public DataReconciliationEngine() {
        reconciliationResults = new Map<String, ObjectReconciliation>();
        detailRecords = new List<Reconciliation_Detail__c>();
    }

    /**
     * Run full reconciliation across all migrated objects
     */
    public Map<String, MigrationOrchestrator.ReconciliationResult> runFullReconciliation() {
        Map<String, MigrationOrchestrator.ReconciliationResult> results =
            new Map<String, MigrationOrchestrator.ReconciliationResult>();

        try {
            // Reconcile products
            results.put('Product', reconcileProducts());

            // Reconcile pricing
            results.put('Pricebook', reconcilePricebooks());
            results.put('PricebookEntry', reconcilePricebookEntries());

            // Reconcile orders
            results.put('Order', reconcileOrders());
            results.put('OrderItem', reconcileOrderItems());

            // Generate report
            generateReconciliationReport(results);

            // Send email to admin
            sendReconciliationEmail(results);

        } catch (Exception e) {
            System.debug('Reconciliation error: ' + e.getMessage());
            throw e;
        }

        return results;
    }

    /**
     * Reconcile Product2 records against source CCRZ products
     */
    private MigrationOrchestrator.ReconciliationResult reconcileProducts() {
        Integer sourceCount = [SELECT COUNT() FROM ccrz__E_Product__c WHERE ccrz__IsActive__c = true];
        Integer targetCount = [SELECT COUNT() FROM Product2 WHERE CreatedDate = TODAY];

        ObjectReconciliation rec = new ObjectReconciliation('Product2', sourceCount, targetCount);

        if (sourceCount != targetCount) {
            rec.passed = false;
            rec.issues.add('Product count mismatch: ' + sourceCount + ' source vs ' + targetCount + ' target');
        }

        // Sample-based field validation
        List<Product2> targetProducts = [
            SELECT Id, Name, ProductCode, Description FROM Product2
            WHERE CreatedDate = TODAY
            ORDER BY CreatedDate DESC
            LIMIT 50
        ];

        Set<String> targetProductCodes = new Set<String>();
        for (Product2 prod : targetProducts) {
            if (String.isNotBlank(prod.ProductCode)) {
                targetProductCodes.add(prod.ProductCode);
            }
        }

        // Verify source products have matching targets
        List<ccrz__E_Product__c> sourceProducts = [
            SELECT ccrz__ProductCode__c, ccrz__ProductName__c
            FROM ccrz__E_Product__c
            WHERE ccrz__IsActive__c = true
            ORDER BY CreatedDate DESC
            LIMIT 50
        ];

        Integer matchCount = 0;
        for (ccrz__E_Product__c srcProd : sourceProducts) {
            if (targetProductCodes.contains(srcProd.ccrz__ProductCode__c)) {
                matchCount++;
            }
        }

        rec.recordsMatched = matchCount;
        rec.sampleSize = sourceProducts.size();

        if (matchCount < sourceProducts.size()) {
            rec.passed = false;
            rec.issues.add('Sample validation: ' + matchCount + '/' + sourceProducts.size() + ' products matched');
        }

        reconciliationResults.put('Product2', rec);
        recordReconciliationDetail('Product2', rec);

        return buildResult(rec);
    }

    /**
     * Reconcile Pricebook2 records
     */
    private MigrationOrchestrator.ReconciliationResult reconcilePricebooks() {
        Integer sourceCount = [SELECT COUNT() FROM ccrz__E_PriceList__c WHERE ccrz__IsActive__c = true];
        Integer targetCount = [SELECT COUNT() FROM Pricebook2 WHERE CreatedDate = TODAY AND IsStandard = false];

        ObjectReconciliation rec = new ObjectReconciliation('Pricebook2', sourceCount, targetCount);

        if (sourceCount != targetCount) {
            rec.passed = false;
            rec.issues.add('Pricebook count mismatch: ' + sourceCount + ' source vs ' + targetCount + ' target');
        }

        reconciliationResults.put('Pricebook2', rec);
        recordReconciliationDetail('Pricebook2', rec);

        return buildResult(rec);
    }

    /**
     * Reconcile PricebookEntry records with pricing validation
     */
    private MigrationOrchestrator.ReconciliationResult reconcilePricebookEntries() {
        Integer sourceCount = [SELECT COUNT() FROM ccrz__E_PriceListItem__c WHERE ccrz__IsActive__c = true];
        Integer targetCount = [SELECT COUNT() FROM PricebookEntry WHERE CreatedDate = TODAY];

        ObjectReconciliation rec = new ObjectReconciliation('PricebookEntry', sourceCount, targetCount);

        if (sourceCount != targetCount) {
            rec.passed = false;
            rec.issues.add('PricebookEntry count mismatch: ' + sourceCount + ' source vs ' + targetCount + ' target');
        }

        // Validate pricing accuracy on sample
        List<PricebookEntry> sampleEntries = [
            SELECT Id, UnitPrice, Product2Id FROM PricebookEntry
            WHERE CreatedDate = TODAY
            LIMIT 100
        ];

        Decimal totalPrice = 0;
        for (PricebookEntry entry : sampleEntries) {
            if (entry.UnitPrice != null) {
                totalPrice += entry.UnitPrice;
            }
        }

        rec.recordsMatched = sampleEntries.size();
        rec.checksumValue = totalPrice;

        reconciliationResults.put('PricebookEntry', rec);
        recordReconciliationDetail('PricebookEntry', rec);

        return buildResult(rec);
    }

    /**
     * Reconcile Order records
     */
    private MigrationOrchestrator.ReconciliationResult reconcileOrders() {
        Integer sourceCount = [SELECT COUNT() FROM ccrz__E_Order__c];
        Integer targetCount = [SELECT COUNT() FROM Order WHERE CreatedDate = TODAY];

        ObjectReconciliation rec = new ObjectReconciliation('Order', sourceCount, targetCount);

        if (sourceCount != targetCount) {
            rec.passed = false;
            rec.issues.add('Order count mismatch: ' + sourceCount + ' source vs ' + targetCount + ' target');
        }

        // Validate order-to-account relationship integrity
        List<Order> ordersWithoutAccount = [
            SELECT Id FROM Order
            WHERE CreatedDate = TODAY AND AccountId = null
        ];

        if (!ordersWithoutAccount.isEmpty()) {
            rec.passed = false;
            rec.issues.add('Found ' + ordersWithoutAccount.size() + ' orders without AccountId');
        }

        // Validate order totals
        List<Order> sampleOrders = [
            SELECT Id, Amount, TotalAmount FROM Order
            WHERE CreatedDate = TODAY
            LIMIT 100
        ];

        Integer ordersWithAmount = 0;
        for (Order order : sampleOrders) {
            if (order.Amount != null && order.Amount > 0) {
                ordersWithAmount++;
            }
        }

        rec.recordsMatched = ordersWithAmount;
        rec.sampleSize = sampleOrders.size();

        reconciliationResults.put('Order', rec);
        recordReconciliationDetail('Order', rec);

        return buildResult(rec);
    }

    /**
     * Reconcile OrderItem records
     */
    private MigrationOrchestrator.ReconciliationResult reconcileOrderItems() {
        Integer sourceCount = [SELECT COUNT() FROM ccrz__E_OrderItem__c];
        Integer targetCount = [SELECT COUNT() FROM OrderItem WHERE CreatedDate = TODAY];

        ObjectReconciliation rec = new ObjectReconciliation('OrderItem', sourceCount, targetCount);

        if (sourceCount != targetCount) {
            rec.passed = false;
            rec.issues.add('OrderItem count mismatch: ' + sourceCount + ' source vs ' + targetCount + ' target');
        }

        // Validate relationship integrity - all items have orders
        List<OrderItem> itemsWithoutOrder = [
            SELECT Id FROM OrderItem
            WHERE CreatedDate = TODAY AND OrderId = null
        ];

        if (!itemsWithoutOrder.isEmpty()) {
            rec.passed = false;
            rec.issues.add('Found ' + itemsWithoutOrder.size() + ' order items without OrderId');
        }

        // Validate all items have products
        List<OrderItem> itemsWithoutProduct = [
            SELECT Id FROM OrderItem
            WHERE CreatedDate = TODAY AND PricebookEntryId = null
        ];

        if (!itemsWithoutProduct.isEmpty()) {
            rec.passed = false;
            rec.issues.add('Found ' + itemsWithoutProduct.size() + ' order items without PricebookEntryId');
        }

        reconciliationResults.put('OrderItem', rec);
        recordReconciliationDetail('OrderItem', rec);

        return buildResult(rec);
    }

    /**
     * Build result object from reconciliation data
     */
    private MigrationOrchestrator.ReconciliationResult buildResult(ObjectReconciliation rec) {
        MigrationOrchestrator.ReconciliationResult result = new MigrationOrchestrator.ReconciliationResult();
        result.passed = rec.passed;
        result.sourceCount = rec.sourceCount;
        result.targetCount = rec.targetCount;
        result.message = rec.objectName + ': ' + (rec.passed ? 'PASSED' : 'FAILED');

        if (!rec.issues.isEmpty()) {
            result.message += ' - Issues: ' + String.join(rec.issues, ' | ');
        }

        return result;
    }

    /**
     * Record reconciliation detail to tracking object
     */
    private void recordReconciliationDetail(String objectName, ObjectReconciliation rec) {
        Reconciliation_Detail__c detail = new Reconciliation_Detail__c();
        detail.Object_Name__c = objectName;
        detail.Source_Count__c = rec.sourceCount;
        detail.Target_Count__c = rec.targetCount;
        detail.Records_Matched__c = rec.recordsMatched;
        detail.Sample_Size__c = rec.sampleSize;
        detail.Status__c = rec.passed ? 'Passed' : 'Failed';
        detail.Issues__c = String.join(rec.issues, '; ').abbreviate(255);

        if (rec.checksumValue != null) {
            detail.Checksum_Value__c = rec.checksumValue;
        }

        detailRecords.add(detail);
    }

    /**
     * Generate comprehensive reconciliation report
     */
    private void generateReconciliationReport(Map<String, MigrationOrchestrator.ReconciliationResult> results) {
        Boolean overallPassed = true;
        String reportDetails = '';

        for (String objectName : results.keySet()) {
            MigrationOrchestrator.ReconciliationResult result = results.get(objectName);
            if (!result.passed) {
                overallPassed = false;
            }
            reportDetails += objectName + ': ' + result.message + '\n';
        }

        reportRecord = new Reconciliation_Report__c();
        reportRecord.Report_Date__c = System.now();
        reportRecord.Overall_Status__c = overallPassed ? 'Passed' : 'Failed';
        reportRecord.Report_Details__c = reportDetails;

        insert reportRecord;

        // Insert all detail records
        if (!detailRecords.isEmpty()) {
            for (Reconciliation_Detail__c detail : detailRecords) {
                detail.Report__c = reportRecord.Id;
            }
            insert detailRecords;
        }
    }

    /**
     * Send reconciliation email to admin
     */
    private void sendReconciliationEmail(Map<String, MigrationOrchestrator.ReconciliationResult> results) {
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(new String[]{'migration-admin@nulogic.com'});
        mail.setSubject('CloudCraze Migration - Reconciliation Report');

        String body = 'Post-Migration Reconciliation Report\n\n';
        body += 'Report ID: ' + reportRecord.Id + '\n';
        body += 'Generated: ' + System.now().format() + '\n\n';

        Integer passCount = 0;
        Integer failCount = 0;

        for (String objectName : results.keySet()) {
            MigrationOrchestrator.ReconciliationResult result = results.get(objectName);
            body += objectName + ': ' + (result.passed ? 'PASSED' : 'FAILED') + '\n';
            body += '  Source: ' + result.sourceCount + ' | Target: ' + result.targetCount + '\n\n';

            if (result.passed) {
                passCount++;
            } else {
                failCount++;
            }
        }

        body += '\nSummary: ' + passCount + ' passed, ' + failCount + ' failed\n';
        body += 'Overall Status: ' + reportRecord.Overall_Status__c + '\n\n';
        body += 'Full report available in Salesforce at: ' + reportRecord.Id;

        mail.setPlainTextBody(body);

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

    /**
     * Reconciliation data wrapper
     */
    private class ObjectReconciliation {
        public String objectName;
        public Integer sourceCount;
        public Integer targetCount;
        public Integer recordsMatched = 0;
        public Integer sampleSize = 0;
        public Decimal checksumValue;
        public Boolean passed = true;
        public List<String> issues = new List<String>();

        public ObjectReconciliation(String name, Integer src, Integer tgt) {
            objectName = name;
            sourceCount = src;
            targetCount = tgt;
        }
    }
}
