/***********************************************************************************************************
 * Name         : CA_ConvertLeadsHelper
 * Purpose      : Helper methods for caConvertLead LWC
 **********************************************************************************************************/
public without sharing class CA_ConvertLeadsHelper {
    /**
     * Checks for duplicate leads based on the provided lead name.
     *
     * @param leadName The name of the lead to check for duplicates
     * @return Id The ID of the duplicate lead if found, null otherwise
     */
    @AuraEnabled
    public static ApexToLwcResponseWrapper checkForDuplicates(String leadName) {
        try {
            List<Account> accounts = [
                SELECT Id
                FROM Account
                WHERE
                    RecordType.DeveloperName = :CA_Constants.RECORD_TYPE_CA
                    AND CA_Account_Name__c = :leadName
                    AND Is_Reverted_to_Lead__c = FALSE
                LIMIT 1
            ];
            Id existingAccountId = accounts.isEmpty() ? null : accounts[0].Id;
            return new ApexToLwcResponseWrapper(existingAccountId, null);
        } catch (Exception ex) {
            ErrorLogger.logError(ex);
            return new ApexToLwcResponseWrapper(null, ex.getMessage());
        }
    }

    /**
     * Converts a Lead to an Account and (optionally) an Opportunity.
     * Deletes the Contact created during conversion and returns an ApexToLwcResponseWrapper
     * containing the resulting record Id or an error message.
     *
     * @param leadId The ID of the Lead record to convert
     * @return ApexToLwcResponseWrapper with data (record Id) on success or error message on failure
     */
    @AuraEnabled
    public static ApexToLwcResponseWrapper convertLead(String leadId, Opportunity opp) {
        LeadStatus convertStatus = [SELECT Id, ApiName FROM LeadStatus WHERE IsConverted = TRUE LIMIT 1];
        SavePoint sp = Database.setSavepoint();
        Database.LeadConvert lc = new Database.LeadConvert();
        lc.setLeadId(leadId);
        lc.setConvertedStatus(convertStatus.ApiName);
        lc.setDoNotCreateOpportunity(true);

        List<Account> revertedToLeadAccounts = [SELECT Id, Current_Account__c FROM Account WHERE Lead__c = :leadId];

        Database.DMLOptions dml = new Database.DMLOptions();
        dml.DuplicateRuleHeader.AllowSave = true;
        try {
            clearPitchSupportFieldsWhenNotRequested(leadId);
            Database.LeadConvertResult lcr = Database.convertLead(lc, dml);
            if (lcr.isSuccess()) {
                Id idToReturn = lcr.getAccountId();
                if (!revertedToLeadAccounts.isEmpty()) {
                    for (Account revertedToLeadAccount : revertedToLeadAccounts) {
                        revertedToLeadAccount.Current_Account__c = idToReturn;
                        revertedToLeadAccount.CA_HasPreviousAccounts__c = false;
                        revertedToLeadAccount.Lead__c = null;
                    }
                    TriggerControl.disableTrigger(AccountTriggerHandler.SELF);
                    Account newAccount = new Account(Id = idToReturn, CA_HasPreviousAccounts__c = true, Lead__c = null);
                    revertedToLeadAccounts.add(newAccount);
                    Database.update(revertedToLeadAccounts, dml);
                    TriggerControl.enableTrigger(AccountTriggerHandler.SELF);
                }
                if (opp != null) {
                    opp.AccountId = lcr.getAccountId();
                    Database.SaveResult saveResult = Database.insert(opp, dml);
                    if (saveResult.isSuccess()) {
                        idToReturn = opp.Id;
                    } else {
                        Database.rollback(sp);
                        return new ApexToLwcResponseWrapper(
                            null,
                            ErrorLogger.getDbErrorMessages(saveResult.getErrors())[0]
                        );
                    }
                }
                deleteContact(lcr.getContactId());
                return new ApexToLwcResponseWrapper(idToReturn, null);
            } else {
                Database.rollback(sp);
                ErrorLogger.logDbErrors(lcr.getErrors(), 'CA_ConvertLeadsHelper', 'convertLead', null);
                return new ApexToLwcResponseWrapper(null, ErrorLogger.getDbErrorMessages(lcr.getErrors())[0]);
            }
        } catch (Exception ex) {
            Database.rollback(sp);
            ErrorLogger.logError(ex);
            return new ApexToLwcResponseWrapper(null, ex.getMessage());
        }
    }

    /**
     * Asynchronously deletes a Contact record to avoid mixed DML errors
     * when deleting Contact records created during Lead conversion.
     *
     * @param contactId The ID of the Contact record to delete
     */
    @future
    public static void deleteContact(Id contactId) {
        delete new Contact(Id = contactId);
    }

    /**
     * Clears all Pitch Support fields on the Lead prior to conversion when the request flag
     * is false. This prevents canceled Pitch Support details from remaining on converted Leads.
     *
     * @param leadId The Lead Id being converted
     */
    private static void clearPitchSupportFieldsWhenNotRequested(Id leadId) {
        FieldVisibilityDependency dependency = CA_Constants.LEAD_PITCH_SUPPORT_FIELD_VISIBILITY_DEPENDENCY;
        String query =
            'SELECT Id, ' +
            dependency.fieldName +
            ', ' +
            String.join(dependency.dependentFields, ',') +
            ' FROM Lead WHERE Id = :leadId AND ' +
            dependency.fieldName +
            ' = FALSE LIMIT 1';
        List<Lead> leadsToClear = Database.query(query);

        if (leadsToClear.isEmpty()) {
            return;
        }

        Lead leadToClear = leadsToClear[0];
        Boolean hasValuesToClear = false;
        for (String fieldName : dependency.dependentFields) {
            if (leadToClear.get(fieldName) != null) {
                hasValuesToClear = true;
                break;
            }
        }

        if (!hasValuesToClear) {
            return;
        }

        Lead fakeOldRecord = new Lead(Id = leadToClear.Id);
        fakeOldRecord.put(dependency.fieldName, dependency.controllingValue);

        FieldVisibilityDependency.handleFieldVisibilityDependencies(
            new List<SObject>{ leadToClear },
            new Map<Id, SObject>{ leadToClear.Id => fakeOldRecord },
            new List<FieldVisibilityDependency>{ dependency }
        );

        TriggerControl.disableTrigger(LeadTriggerHandler.SELF);
        update leadToClear;
        TriggerControl.enableTrigger(LeadTriggerHandler.SELF);
    }
}