/***********************************************************************************************************
 * Name         : CA_LeadsDataLoaderHelper
 * Purpose      : Helper methods for caLeadsDataLoader LWC
 **********************************************************************************************************/
public with sharing class CA_LeadsDataLoaderHelper {
    /**
     * Finds duplicate leads and validates owners.
     *
     * @param leads The list of LeadWrapper records to validate
     * @return A list of ValidationResultWrapper objects containing duplicate lead information
     */
    @AuraEnabled
    public static ApexToLwcResponseWrapper findDuplicatesAndValidateOwner(List<LeadWrapper> leads) {
        SavePoint sp = Database.setSavepoint();
        List<ValidationResultWrapper> resultWrapper = new List<ValidationResultWrapper>();
        try {
            Set<String> ownersSet = new Set<String>();
            Map<String, Id> usersMap = new Map<String, Id>();
            for (LeadWrapper wrapper : leads) {
                if (wrapper.Owner != null) {
                    ownersSet.add(String.valueOf(wrapper.Owner));
                }
            }
            if (!ownersSet.isEmpty()) {
                for (AggregateResult psAssignment : [
                    SELECT Assignee.Id, Assignee.Name
                    FROM PermissionSetAssignment
                    WHERE
                        PermissionSet.Name IN :CA_Constants.PERMISSION_SETS
                        AND Assignee.IsActive = TRUE
                        AND Assignee.Name IN :ownersSet
                    GROUP BY Assignee.Id, Assignee.Name
                    ORDER BY Assignee.Name
                ]) {
                    usersMap.put((String) psAssignment.get('Name'), (Id) psAssignment.get('Id'));
                }
            }
            List<Lead> leadsToValidate = new List<Lead>();
            for (LeadWrapper wrapper : leads) {
                Lead leadToValidate = new Lead(
                    RecordTypeId = LeadTriggerHelper.CA_RECTYPE_ID,
                    CA_Lead_Name__c = wrapper.Name
                );
                if (usersMap.containsKey(wrapper.Owner)) {
                    leadToValidate.OwnerId = usersMap.get(wrapper.Owner);
                }
                leadsToValidate.add(leadToValidate);
            }

            List<Database.SaveResult> saveResults = Database.insert(leadsToValidate, false);
            for (Integer i = 0; i < saveResults.size(); i++) {
                resultWrapper.add(
                    new ValidationResultWrapper(
                        leadsToValidate[i].CA_Lead_Name__c,
                        leads[i].Owner,
                        usersMap.get(leads[i].Owner)
                    )
                );
                if (!saveResults[i].isSuccess()) {
                    for (Database.Error saveResultError : saveResults[i].getErrors()) {
                        if (saveResultError instanceof Database.DuplicateError) {
                            Datacloud.DuplicateResult duplicateResult = ((Database.DuplicateError) saveResultError)
                                .getDuplicateResult();
                            for (Datacloud.MatchResult matchResult : duplicateResult.getMatchResults()) {
                                for (Datacloud.MatchRecord matchRecord : matchResult.getMatchRecords()) {
                                    if (matchRecord.getRecord() instanceof Lead) {
                                        Lead duplicateLead = (Lead) matchRecord.getRecord();
                                        resultWrapper[i].leads.add(duplicateLead);
                                    } else if (matchRecord.getRecord() instanceof Account) {
                                        Account duplicateAccount = (Account) matchRecord.getRecord();
                                        resultWrapper[i].accounts.add(duplicateAccount);
                                    }
                                }
                            }
                        } else {
                            resultWrapper[i].errors.add(saveResultError.getMessage());
                        }
                    }
                }
            }
        } catch (Exception ex) {
            ErrorLogger.logError(ex);
            return new ApexToLwcResponseWrapper(null, ex.getMessage());
        } finally {
            Database.rollback(sp);
        }
        return new ApexToLwcResponseWrapper(resultWrapper, null);
    }

    /**
     * @description Inserts a list of Lead records with specific configurations and field assignments.
     *  Automatically assigns the CA Record Type ID and copies the Name to CA_Lead_Name__c field.
     * @param leads List<Lead> - The list of Lead records to be inserted into the database
     * @param ignoreDuplicates Boolean - A flag to determine whether to ignore duplicate rules during insertion
     * @return String - A JSON-serialized result of the Database.insert operation containing
     *  the insertion results with IDs, success status, and any error messages
     */
    @AuraEnabled
    public static ApexToLwcResponseWrapper insertLeads(List<Lead> leads, Boolean ignoreDuplicates) {
        try {
            for (Lead l : leads) {
                l.RecordTypeId = LeadTriggerHelper.CA_RECTYPE_ID;
                l.CA_Lead_Name__c = l.Name;
            }

            Database.DMLOptions dml = new Database.DMLOptions();
            dml.DuplicateRuleHeader.allowSave = ignoreDuplicates;
            dml.OptAllOrNone = false;

            return new ApexToLwcResponseWrapper(JSON.serialize(Database.insert(leads, dml)), null);
        } catch (Exception ex) {
            ErrorLogger.logError(ex);
            return new ApexToLwcResponseWrapper(null, ex.getMessage());
        }
    }

    public class LeadWrapper {
        @AuraEnabled
        public String Name { get; set; }
        @AuraEnabled
        public String Owner { get; set; }
    }

    public class ValidationResultWrapper {
        @AuraEnabled
        public String name;
        @AuraEnabled
        public List<Account> accounts;
        @AuraEnabled
        public List<Lead> leads;
        @AuraEnabled
        public String owner;
        @AuraEnabled
        public String ownerId;
        @AuraEnabled
        public List<String> errors;

        public ValidationResultWrapper(String name, String owner, String ownerId) {
            this.name = name;
            this.owner = owner;
            this.ownerId = ownerId;
            this.accounts = new List<Account>();
            this.leads = new List<Lead>();
            this.errors = new List<String>();
        }
    }
}
