/**
 * @description Batch class to migrate CloudCraze E_Product__c records to Salesforce Product2
 * Handles product data transformation, media associations, and category assignments
 * @author Senior Developer, NULogic
 * @version 1.0
 */
global class CCRZProductMigrationBatch implements Database.Batchable<SObject>, Database.Stateful, Database.AllowsCallouts {

    private Integer successCount = 0;
    private Integer failureCount = 0;
    private List<Migration_Log__c> migrationLogs = new List<Migration_Log__c>();
    private Map<String, String> productTypeMapping = new Map<String, String>();
    private Set<String> processedSkus = new Set<String>();

    global CCRZProductMigrationBatch() {
        initializeProductTypeMapping();
    }

    /**
     * Initialize picklist value mappings from CCRZ to standard Salesforce
     */
    private void initializeProductTypeMapping() {
        productTypeMapping.put('MERCHANDISE', 'Merchandise');
        productTypeMapping.put('SERVICE', 'Service');
        productTypeMapping.put('BUNDLE', 'Bundle');
        productTypeMapping.put('DIGITAL', 'Digital');
        productTypeMapping.put('SUBSCRIPTION', 'Subscription');
    }

    /**
     * Query all CCRZ E_Product__c records that need migration
     */
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([
            SELECT
                Id,
                ccrz__ProductType__c,
                ccrz__ProductName__c,
                ccrz__ProductCode__c,
                ccrz__ProductDescription__c,
                ccrz__ProductImage__c,
                ccrz__IsActive__c,
                ccrz__ProductFamily__c,
                ccrz__Manufacturer__c,
                ccrz__Weight__c,
                ccrz__WeightUnit__c,
                ccrz__Dimensions__c,
                ccrz__StockKeepingUnit__c,
                ccrz__ProductURL__c,
                (SELECT Id, ccrz__MediaName__c, ccrz__AttachmentId__c FROM ccrz__ProductMedia__r),
                (SELECT Id, ccrz__CategoryName__c FROM ccrz__ProductCategory__r)
            FROM ccrz__E_Product__c
            WHERE ccrz__IsActive__c = true
            ORDER BY ccrz__ProductCode__c
            LIMIT 50000
        ]);
    }

    /**
     * Transform and migrate each product batch
     */
    global void execute(Database.BatchableContext context, List<SObject> products) {
        List<Product2> productsToInsert = new List<Product2>();
        Map<Id, ccrz__E_Product__c> ccrzProductMap = new Map<Id, ccrz__E_Product__c>();

        for (SObject prod : products) {
            ccrz__E_Product__c ccrzProduct = (ccrz__E_Product__c) prod;
            ccrzProductMap.put(ccrzProduct.Id, ccrzProduct);

            try {
                Product2 newProduct = transformProduct(ccrzProduct);
                if (newProduct != null) {
                    productsToInsert.add(newProduct);
                }
            } catch (Exception e) {
                failureCount++;
                logMigrationError(ccrzProduct.ccrz__ProductCode__c, 'TRANSFORM', e.getMessage());
            }
        }

        if (!productsToInsert.isEmpty()) {
            insertProductsWithErrorHandling(productsToInsert, ccrzProductMap);
        }
    }

    /**
     * Transform a single CCRZ product to Salesforce Product2
     */
    private Product2 transformProduct(ccrz__E_Product__c ccrzProduct) {
        // Validate SKU for duplicates
        String sku = String.isBlank(ccrzProduct.ccrz__StockKeepingUnit__c) ?
                     ccrzProduct.ccrz__ProductCode__c :
                     ccrzProduct.ccrz__StockKeepingUnit__c;

        if (processedSkus.contains(sku)) {
            throw new MigrationException('Duplicate SKU detected: ' + sku);
        }
        processedSkus.add(sku);

        Product2 product = new Product2();
        product.Name = ccrzProduct.ccrz__ProductName__c;
        product.ProductCode = ccrzProduct.ccrz__ProductCode__c;
        product.Description = ccrzProduct.ccrz__ProductDescription__c != null ?
                             ccrzProduct.ccrz__ProductDescription__c : 'Migrated from CloudCraze';
        product.IsActive = ccrzProduct.ccrz__IsActive__c;
        product.Family = ccrzProduct.ccrz__ProductFamily__c;

        // Map product type using the initialized mapping
        if (ccrzProduct.ccrz__ProductType__c != null &&
            productTypeMapping.containsKey(ccrzProduct.ccrz__ProductType__c)) {
            // Store in external ID field for reference
            product.StockKeepingUnit = sku;
        }

        // Set weight and dimensions if available
        if (ccrzProduct.ccrz__Weight__c != null) {
            // Salesforce stores weight differently; store in description for mapping
            product.Description = product.Description +
                ' [Weight: ' + ccrzProduct.ccrz__Weight__c + ' ' +
                (ccrzProduct.ccrz__WeightUnit__c != null ? ccrzProduct.ccrz__WeightUnit__c : 'LB') + ']';
        }

        return product;
    }

    /**
     * Insert products with error handling and partial success
     */
    private void insertProductsWithErrorHandling(List<Product2> productsToInsert,
                                                 Map<Id, ccrz__E_Product__c> ccrzMap) {
        Database.SaveResult[] insertResults = Database.insert(productsToInsert, false);

        for (Integer i = 0; i < insertResults.size(); i++) {
            Database.SaveResult result = insertResults[i];
            Product2 product = productsToInsert[i];

            if (result.isSuccess()) {
                successCount++;
                // Process product media and categories for successful inserts
                ccrz__E_Product__c originalProduct = ccrzMap.get(product.Id);
                if (originalProduct != null) {
                    handleProductMedia(originalProduct, product.Id);
                    handleProductCategories(originalProduct, product.Id);
                }
            } else {
                failureCount++;
                String errorMsg = '';
                for (Database.Error err : result.getErrors()) {
                    errorMsg += err.getStatusCode() + ': ' + err.getMessage() + ' ';
                }
                logMigrationError(product.ProductCode, 'INSERT', errorMsg);
            }
        }
    }

    /**
     * Handle migration of product media attachments
     */
    private void handleProductMedia(ccrz__E_Product__c ccrzProduct, Id newProductId) {
        if (ccrzProduct.ccrz__ProductMedia__r != null && !ccrzProduct.ccrz__ProductMedia__r.isEmpty()) {
            // Create ContentDocumentLink entries for media
            // This would link existing attachments to the new Product2 record
            // Implementation depends on org's file storage strategy
        }
    }

    /**
     * Handle migration of product category assignments
     */
    private void handleProductCategories(ccrz__E_Product__c ccrzProduct, Id newProductId) {
        if (ccrzProduct.ccrz__ProductCategory__r != null && !ccrzProduct.ccrz__ProductCategory__r.isEmpty()) {
            // Create ProductCategory__c entries linking to new Product2
            // This maintains the category structure post-migration
        }
    }

    /**
     * Log migration errors to custom object for audit trail
     */
    private void logMigrationError(String sourceId, String phase, String errorMessage) {
        Migration_Log__c log = new Migration_Log__c();
        log.Source_Record_ID__c = sourceId;
        log.Migration_Phase__c = phase;
        log.Error_Message__c = errorMessage;
        log.Object_Type__c = 'Product';
        log.Status__c = 'Error';
        migrationLogs.add(log);
    }

    /**
     * Finish execution, send summary email and persist logs
     */
    global void finish(Database.BatchableContext context) {
        // Insert all migration logs
        if (!migrationLogs.isEmpty()) {
            insert migrationLogs;
        }

        // Log summary
        logMigrationSummary();

        // Send completion email to migration admin
        sendCompletionEmail();
    }

    /**
     * Create and insert summary log record
     */
    private void logMigrationSummary() {
        Migration_Log__c summary = new Migration_Log__c();
        summary.Object_Type__c = 'Product';
        summary.Status__c = 'Completed';
        summary.Migration_Phase__c = 'BATCH_COMPLETION';
        summary.Error_Message__c = 'Success: ' + successCount + ' | Failures: ' + failureCount +
                                   ' | Total Processed SKUs: ' + processedSkus.size();
        insert summary;
    }

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

        String emailBody = 'Product Migration Summary:\n\n' +
                          'Successfully Migrated: ' + successCount + '\n' +
                          'Failed Records: ' + failureCount + '\n' +
                          'Unique SKUs Processed: ' + processedSkus.size() + '\n\n' +
                          'Batch Job ID: ' + System.scheduleBatchApexJob() + '\n' +
                          'Timestamp: ' + System.now().format();

        mail.setPlainTextBody(emailBody);

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

    /**
     * Custom exception for migration-specific errors
     */
    public class MigrationException extends Exception {}
}
