package com.datai.integration.service.impl;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Supplier;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.datai.common.utils.DateUtils;
import com.datai.common.utils.SecurityUtils;
import com.datai.integration.model.domain.DataiIntegrationField;
import com.datai.integration.model.param.DataiSyncParam;
import com.datai.salesforce.common.constant.SalesforceConstants;
import com.datai.salesforce.common.utils.SoqlBuilder;
import com.datai.integration.util.ConvertUtil;
import com.sforce.soap.partner.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.datai.integration.mapper.DataiIntegrationBatchMapper;
import com.datai.integration.model.domain.DataiIntegrationBatch;
import com.datai.integration.service.IDataiIntegrationBatchService;
import com.datai.common.core.domain.model.LoginUser;
import com.datai.integration.model.domain.DataiIntegrationBatchHistory;
import com.datai.integration.service.IDataiIntegrationBatchHistoryService;
import com.datai.integration.service.IDataiIntegrationFieldService;
import com.datai.integration.service.IDataiIntegrationSyncLogService;
import com.datai.integration.mapper.CustomMapper;
import com.datai.integration.factory.impl.SOAPConnectionFactory;
import com.datai.integration.core.IPartnerV1Connection;
import com.sforce.soap.partner.sobject.SObject;
import com.sforce.ws.ConnectionException;
import lombok.extern.slf4j.Slf4j;


/**
 * 数据批次Service业务层处理
 *
 * @author datai
 * @date 2025-12-24
 */
@Service
@Slf4j
public class DataiIntegrationBatchServiceImpl implements IDataiIntegrationBatchService {
    @Autowired
    private DataiIntegrationBatchMapper dataiIntegrationBatchMapper;

    @Autowired
    private IDataiIntegrationBatchHistoryService batchHistoryService;

    @Autowired
    private IDataiIntegrationFieldService integrationFieldService;

    @Autowired
    private CustomMapper customMapper;

    @Autowired
    private SOAPConnectionFactory soapConnectionFactory;

    @Autowired
    private IDataiIntegrationSyncLogService dataiIntegrationSyncLogService;

    /**
     * 查询数据批次
     *
     * @param id 数据批次主键
     * @return 数据批次
     */
    @Override
    public DataiIntegrationBatch selectDataiIntegrationBatchById(Integer id)
    {
        return dataiIntegrationBatchMapper.selectDataiIntegrationBatchById(id);
    }

    /**
     * 查询数据批次列表
     *
     * @param dataiIntegrationBatch 数据批次
     * @return 数据批次
     */
    @Override
    public List<DataiIntegrationBatch> selectDataiIntegrationBatchList(DataiIntegrationBatch dataiIntegrationBatch)
    {
        return dataiIntegrationBatchMapper.selectDataiIntegrationBatchList(dataiIntegrationBatch);
    }

    /**
     * 新增数据批次
     *
     * @param dataiIntegrationBatch 数据批次
     * @return 结果
     */
    @Override
    public int insertDataiIntegrationBatch(DataiIntegrationBatch dataiIntegrationBatch)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String username = loginUser.getUsername();

                dataiIntegrationBatch.setCreateTime(DateUtils.getNowDate());
                dataiIntegrationBatch.setUpdateTime(DateUtils.getNowDate());
                dataiIntegrationBatch.setCreateBy(username);
                dataiIntegrationBatch.setUpdateBy(username);
            return dataiIntegrationBatchMapper.insertDataiIntegrationBatch(dataiIntegrationBatch);
    }

    /**
     * 修改数据批次
     *
     * @param dataiIntegrationBatch 数据批次
     * @return 结果
     */
    @Override
    public int updateDataiIntegrationBatch(DataiIntegrationBatch dataiIntegrationBatch)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String username = loginUser.getUsername();

                dataiIntegrationBatch.setUpdateTime(DateUtils.getNowDate());
                dataiIntegrationBatch.setUpdateBy(username);
        return dataiIntegrationBatchMapper.updateDataiIntegrationBatch(dataiIntegrationBatch);
    }

    /**
     * 批量删除数据批次
     *
     * @param ids 需要删除的数据批次主键
     * @return 结果
     */
    @Override
    public int deleteDataiIntegrationBatchByIds(Integer[] ids)
    {
        return dataiIntegrationBatchMapper.deleteDataiIntegrationBatchByIds(ids);
    }

    /**
     * 删除数据批次信息
     *
     * @param id 数据批次主键
     * @return 结果
     */
    @Override
    public int deleteDataiIntegrationBatchById(Integer id)
    {
        return dataiIntegrationBatchMapper.deleteDataiIntegrationBatchById(id);
    }

    /**
     * 重试失败的批次
     *
     * @param id 批次ID
     * @return 结果
     */
    @Override
    public boolean retryFailed(Integer id) {
        try {
            log.info("开始重试失败的批次，批次ID: {}", id);

            DataiIntegrationBatch batch = selectDataiIntegrationBatchById(id);
            if (batch == null) {
                log.error("批次不存在，批次ID: {}", id);
                return false;
            }

            DataiIntegrationBatchHistory queryHistory = new DataiIntegrationBatchHistory();
            queryHistory.setBatchId(id);
            queryHistory.setSyncStatus(false);
            List<DataiIntegrationBatchHistory> failedHistories = batchHistoryService.selectDataiIntegrationBatchHistoryList(queryHistory);

            if (failedHistories.isEmpty()) {
                log.warn("批次没有失败的同步记录，批次ID: {}", id);
                return true;
            }

            log.info("批次 {} 共有 {} 条失败的同步记录，准备重试", id, failedHistories.size());

            boolean retryResult = syncObjectDataByBatch(batch.getApi(), id);

            if (retryResult) {
                log.info("批次 {} 重试成功", id);
            } else {
                log.error("批次 {} 重试失败", id);
            }

            return retryResult;
        } catch (Exception e) {
            log.error("重试批次 {} 时发生异常", id, e);
            return false;
        }
    }

    /**
     * 获取批次同步统计信息
     *
     * @param id 批次ID
     * @return 统计信息
     */
    @Override
    public Map<String, Object> getSyncStatistics(Integer id) {
        Map<String, Object> statistics = new HashMap<>();

        try {
            DataiIntegrationBatch batch = selectDataiIntegrationBatchById(id);
            if (batch == null) {
                log.error("批次不存在，批次ID: {}", id);
                statistics.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                statistics.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_NOT_EXIST);
                return statistics;
            }

            DataiIntegrationBatchHistory queryHistory = new DataiIntegrationBatchHistory();
            queryHistory.setBatchId(id);
            List<DataiIntegrationBatchHistory> histories = batchHistoryService.selectDataiIntegrationBatchHistoryList(queryHistory);

            int totalCount = histories.size();
            int successCount = 0;
            int failedCount = 0;
            int totalSyncNum = 0;
            long totalCost = 0L;
            long minCost = Long.MAX_VALUE;
            long maxCost = 0L;

            for (DataiIntegrationBatchHistory history : histories) {
                if (history.getSyncStatus()) {
                    successCount++;
                } else {
                    failedCount++;
                }

                if (history.getSyncNum() != null) {
                    totalSyncNum += history.getSyncNum();
                }

                if (history.getCost() != null) {
                    totalCost += history.getCost();
                    minCost = Math.min(minCost, history.getCost());
                    maxCost = Math.max(maxCost, history.getCost());
                }
            }

            long avgCost = totalCount > 0 ? totalCost / totalCount : 0;
            if (minCost == Long.MAX_VALUE) {
                minCost = 0L;
            }

            statistics.put(SalesforceConstants.RESULT_KEY_SUCCESS, true);
            statistics.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_GET_STATISTICS_SUCCESS);
            int finalSuccessCount = successCount;
            int finalFailedCount = failedCount;
            int finalTotalSyncNum = totalSyncNum;
            long finalTotalCost = totalCost;
            long finalMinCost = minCost;
            long finalMaxCost = maxCost;
            statistics.put(SalesforceConstants.RESULT_KEY_DATA, new HashMap<String, Object>() {{
                put(SalesforceConstants.RESULT_KEY_BATCH_ID, id);
                put(SalesforceConstants.RESULT_KEY_API, batch.getApi());
                put(SalesforceConstants.RESULT_KEY_LABEL, batch.getLabel());
                put(SalesforceConstants.RESULT_KEY_SYNC_TYPE, batch.getSyncType());
                put(SalesforceConstants.RESULT_KEY_SF_NUM, batch.getSfNum());
                put(SalesforceConstants.RESULT_KEY_DB_NUM, batch.getDbNum());
                put(SalesforceConstants.RESULT_KEY_TOTAL_COUNT_STAT, totalCount);
                put(SalesforceConstants.RESULT_KEY_SUCCESS_COUNT_STAT, finalSuccessCount);
                put(SalesforceConstants.RESULT_KEY_FAILED_COUNT_STAT, finalFailedCount);
                put(SalesforceConstants.RESULT_KEY_SUCCESS_RATE, totalCount > 0 ? (double) finalSuccessCount / totalCount * 100 : 0);
                put(SalesforceConstants.RESULT_KEY_TOTAL_SYNC_NUM, finalTotalSyncNum);
                put(SalesforceConstants.RESULT_KEY_TOTAL_COST, finalTotalCost);
                put(SalesforceConstants.RESULT_KEY_AVG_COST, avgCost);
                put(SalesforceConstants.RESULT_KEY_MIN_COST, finalMinCost);
                put(SalesforceConstants.RESULT_KEY_MAX_COST, finalMaxCost);
                put(SalesforceConstants.RESULT_KEY_FIRST_SYNC_TIME, batch.getFirstSyncTime());
                put(SalesforceConstants.RESULT_KEY_LAST_SYNC_TIME, batch.getLastSyncTime());
                put(SalesforceConstants.RESULT_KEY_SYNC_STATUS, batch.getSyncStatus());
            }});

            log.info("获取批次 {} 统计信息成功", id);
        } catch (Exception e) {
            log.error("获取批次 {} 统计信息时发生异常", id, e);
            statistics.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            statistics.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_GET_STATISTICS_FAILED + e.getMessage());
        }

        return statistics;
    }

    @Override
    public Map<String, Object> syncBatchData(Integer id) {
        Map<String, Object> result = new HashMap<>();

        try {
            log.info("开始同步批次数据，批次ID: {}", id);

            DataiIntegrationBatch batch = selectDataiIntegrationBatchById(id);
            if (batch == null) {
                log.error("批次不存在，批次ID: {}", id);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_NOT_EXIST);
                return result;
            }

            String objectApi = batch.getApi();

            log.info("准备同步对象 {} 的批次 {} 数据", objectApi, id);

            boolean syncResult = syncObjectDataByBatch(objectApi, id);

            batch = selectDataiIntegrationBatchById(id);
            
            if (syncResult) {
                log.info("批次 {} 数据同步成功", id);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, true);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_SYNC_SUCCESS);
                result.put(SalesforceConstants.RESULT_KEY_BATCH_ID, id);
                result.put(SalesforceConstants.RESULT_KEY_API, objectApi);
                result.put(SalesforceConstants.RESULT_KEY_LABEL, batch.getLabel());
                result.put(SalesforceConstants.RESULT_KEY_SYNC_NUM, batch.getDbNum());
            } else {
                log.error("批次 {} 数据同步失败", id);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_SYNC_FAILED);
                result.put(SalesforceConstants.RESULT_KEY_BATCH_ID, id);
                result.put(SalesforceConstants.RESULT_KEY_API, objectApi);
                result.put(SalesforceConstants.RESULT_KEY_SYNC_NUM, batch.getDbNum() != null ? batch.getDbNum() : 0);
            }

        } catch (Exception e) {
            log.error("同步批次 {} 数据时发生异常", id, e);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_SYNC_BATCH_DATA_FAILED + e.getMessage());
        }

        return result;
    }

    /**
     * 同步Salesforce对象的指定批次数据
     *
     * @param objectApi Salesforce对象API
     * @param batchId   批次ID
     * @return 同步结果
     */
    private boolean syncObjectDataByBatch(String objectApi, Integer batchId) {
        log.info("准备同步Salesforce对象的指定批次数据，对象API: {}, 批次ID: {}", objectApi, batchId);
        
        if (objectApi == null || objectApi.trim().isEmpty() || batchId == null ) {
            log.error("对象API或批次ID为空，无法同步指定批次数据");
            return false;
        }
        
        DataiIntegrationBatch batch = null;
        DataiIntegrationBatchHistory batchHistory = new DataiIntegrationBatchHistory();
        long startTime = System.currentTimeMillis();
        LocalDateTime syncStartTime = LocalDateTime.now();
        
        try {
            batch = selectDataiIntegrationBatchById(batchId);
            if (batch == null) {
                log.error("批次不存在，批次ID: {}", batchId);
                return false;
            }
            
            IPartnerV1Connection connection = retryOperation(() -> soapConnectionFactory.getConnection("source"), SalesforceConstants.MAX_RETRY_COUNT, SalesforceConstants.RETRY_DELAY_MS);

            List<String> fieldList = getSalesforceObjectFields(connection, objectApi);
            log.info("获取到对象 {} 的字段列表: {}", objectApi, fieldList);

            DataiSyncParam param = new DataiSyncParam();
            param.setApi(objectApi);
            param.setSelect(String.join(",", fieldList));
            param.setBatchField(batch.getBatchField());

            if (integrationFieldService.isDeletedFieldExists(objectApi)) {
                param.setIsDeleted(true);
            }

            if (batch.getSyncStartDate() != null) {
                param.setBeginDate(java.sql.Timestamp.valueOf(batch.getSyncStartDate()));
            }
            if (batch.getSyncEndDate() != null) {
                param.setEndDate(java.sql.Timestamp.valueOf(batch.getSyncEndDate()));
            }

            int sfTotalCount = querySalesforceDataCount(connection, param);
            log.info("对象 {} 批次 {} Salesforce中共有 {} 条记录需要同步", objectApi, batchId, sfTotalCount);
            
            int dbProcessedCount = executeQueryAndProcessData(connection, param, fieldList);
            log.info("对象 {} 批次 {} 数据同步完成，共处理 {} 条记录", objectApi, batchId, dbProcessedCount);
            
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            LocalDateTime syncEndTime = LocalDateTime.now();
            
            batchHistory.setApi(objectApi);
            batchHistory.setLabel(batch.getLabel());
            batchHistory.setBatchId(batchId);
            batchHistory.setBatchField(batch.getBatchField());
            batchHistory.setSyncNum(dbProcessedCount);
            batchHistory.setSyncType(batch.getSyncType());
            batchHistory.setSyncStatus(true);
            batchHistory.setStartTime(syncStartTime);
            batchHistory.setEndTime(syncEndTime);
            batchHistory.setCost(duration);
            batchHistory.setSyncStartTime(syncStartTime);
            batchHistory.setSyncEndTime(syncEndTime);
            batchHistoryService.insertDataiIntegrationBatchHistory(batchHistory);
            log.info("批次 {} 历史记录已保存，同步数据量: {}, 耗时: {}ms", batchId, dbProcessedCount, duration);
            
            batch.setSfNum(sfTotalCount);
            batch.setDbNum(dbProcessedCount);
            batch.setSyncStatus(true);
            if (batch.getFirstSyncTime() == null) {
                batch.setFirstSyncTime(syncStartTime);
            }
            batch.setLastSyncTime(syncEndTime);
            batch.setUpdateTime(DateUtils.getNowDate());
            updateDataiIntegrationBatch(batch);
            log.info("批次 {} 信息已更新，SF数据量: {}, 本地数据量: {}, 同步状态: {}, 首次同步时间: {}, 最后同步时间: {}", 
                    batchId, sfTotalCount, dbProcessedCount, true, batch.getFirstSyncTime(), syncEndTime);
            
            insertSyncLog(objectApi, batch.getLabel(), batch.getSyncType(), batchId, true, null, duration);
            
            return true;
        } catch (Exception e) {
            log.error("同步Salesforce对象指定批次数据失败，对象API: {}, 批次ID: {}", objectApi, batchId, e);
            
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            LocalDateTime syncEndTime = LocalDateTime.now();
            
            batchHistory.setApi(objectApi);
            batchHistory.setLabel(batch != null ? batch.getLabel() : "");
            batchHistory.setBatchId(batchId);
            batchHistory.setBatchField(batch != null ? batch.getBatchField() : "");
            batchHistory.setSyncNum(0);
            batchHistory.setSyncType(batch != null ? batch.getSyncType() : "");
            batchHistory.setSyncStatus(false);
            batchHistory.setStartTime(syncStartTime);
            batchHistory.setEndTime(syncEndTime);
            batchHistory.setCost(duration);
            batchHistory.setSyncStartTime(syncStartTime);
            batchHistory.setSyncEndTime(syncEndTime);
            batchHistoryService.insertDataiIntegrationBatchHistory(batchHistory);
            log.info("批次 {} 失败历史记录已保存，耗时: {}ms", batchId, duration);
            
            if (batch != null) {
                batch.setSyncStatus(false);
                batch.setLastSyncTime(syncEndTime);
                batch.setUpdateTime(DateUtils.getNowDate());
                updateDataiIntegrationBatch(batch);
                log.info("批次 {} 信息已更新，同步状态: {}, 结束时间: {}", batchId, false, syncEndTime);
            }
            
            insertSyncLog(objectApi, batch != null ? batch.getLabel() : "", batch != null ? batch.getSyncType() : "", batchId, false, e.getMessage(), duration);
            
            return false;
        }
    }

    private void insertSyncLog(String objectApi, String label, String syncType, Integer batchId, boolean success, String errorMessage, long duration) {
        try {
            com.datai.integration.model.domain.DataiIntegrationSyncLog syncLog = new com.datai.integration.model.domain.DataiIntegrationSyncLog();
            syncLog.setObjectApi(objectApi);
            syncLog.setBatchId(batchId);
            syncLog.setOperationType("FULL".equals(syncType) ? "全量同步" : "增量同步");
            syncLog.setOperationStatus(success ? "成功" : "失败");
            syncLog.setErrorMessage(errorMessage);
            syncLog.setExecutionTime(new java.math.BigDecimal(duration / (double) SalesforceConstants.MILLIS_PER_SECOND));
            syncLog.setCreateTime(DateUtils.getNowDate());
            
            try {
                LoginUser loginUser = SecurityUtils.getLoginUser();
                if (loginUser != null && loginUser.getDeptId() != null) {
                    syncLog.setDeptId(loginUser.getDeptId());
                }
            } catch (Exception ex) {
                log.warn("获取部门ID失败: {}", ex.getMessage());
            }
            
            dataiIntegrationSyncLogService.insertDataiIntegrationSyncLog(syncLog);
            log.info("同步日志已记录，对象API: {}, 操作类型: {}, 状态: {}", objectApi, syncLog.getOperationType(), syncLog.getOperationStatus());
        } catch (Exception e) {
            log.error("插入同步日志失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 重试操作
     *
     * @param operation 操作
     * @param maxRetries 最大重试次数
     * @param delayMs 延迟毫秒数
     * @param <T> 返回类型
     * @return 操作结果
     */
    private <T> T retryOperation(Supplier<T> operation, int maxRetries, long delayMs) {
        int retries = 0;
        while (true) {
            try {
                return operation.get();
            } catch (Exception e) {
                retries++;
                if (retries >= maxRetries) {
                    log.error("操作失败，已达到最大重试次数: {}", maxRetries, e);
                    throw e;
                }
                try {
                    log.warn("操作失败，将在 {} 毫秒后重试，当前重试次数: {}", delayMs, retries);
                    Thread.sleep(delayMs);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    log.error("重试延迟时线程被中断", ie);
                    throw new RuntimeException(ie);
                }
            }
        }
    }

    /**
     * 获取Salesforce对象字段列表
     *
     * @param connection SOAP连接
     * @param objectApi  对象API名称
     * @return 字段列表
     * @throws ConnectionException 连接异常
     */
    private List<String> getSalesforceObjectFields(IPartnerV1Connection connection, String objectApi) throws ConnectionException {
        List<String> fields = new ArrayList<>();

        DescribeSObjectResult describeResult = connection.describeSObject(objectApi);
        Field[] objectFields = describeResult.getFields();

        for (Field field : objectFields) {
            if (field.getType() != null && "base64".equalsIgnoreCase(field.getType().toString())) {
                continue;
            }
            fields.add(field.getName());
        }

        if (!fields.contains("Id")) {
            fields.add("Id");
        }
        if (!fields.contains("Name")) {
            fields.add("Name");
        }

        return fields;
    }

    /**
     * 查询Salesforce数据量
     *
     * @param connection Salesforce连接
     * @param param 查询参数
     * @return 符合条件的总记录数
     */
    private int querySalesforceDataCount(IPartnerV1Connection connection, DataiSyncParam param) {
        int totalCount = 0;
        
        try {
            String countQuery = buildCountQuery(param);
            log.info("查询数据量SQL: {}", countQuery);
            
            QueryResult result = connection.queryAll(countQuery);
            
            if (result != null && result.getRecords() != null && result.getRecords().length > 0) {
                SObject record = result.getRecords()[0];
                Object countValue = record.getField("expr0");
                if (countValue != null) {
                    totalCount = Integer.parseInt(countValue.toString());
                }
            }
            
            log.info("对象 {} 符合条件的总记录数: {}", param.getApi(), totalCount);
        } catch (Exception e) {
            log.error("查询数据量时发生异常，对象API: {}", param.getApi(), e);
        }
        
        return totalCount;
    }

    /**
     * 构建COUNT查询语句
     *
     * @param param 查询参数
     * @return SOQL COUNT查询语句
     */
    private String buildCountQuery(DataiSyncParam param) {
        SoqlBuilder builder = new SoqlBuilder();
        builder.from(param.getApi());
        
        if (param.getIsDeleted() != null && param.getIsDeleted()) {
            builder.where("IsDeleted = false");
        }
        
        if (param.getBeginDate() != null && param.getEndDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginDate())
                   .whereLe(param.getBatchField(), param.getEndDate());
        } else if (param.getBeginDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginDate());
        } else if (param.getEndDate() != null) {
            builder.whereLe(param.getBatchField(), param.getEndDate());
        }
        
        if (param.getBeginCreateDate() != null && param.getEndCreateDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginCreateDate())
                   .whereLe(param.getBatchField(), param.getEndCreateDate());
        } else if (param.getBeginCreateDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginCreateDate());
        } else if (param.getEndCreateDate() != null) {
            builder.whereLe(param.getBatchField(), param.getEndCreateDate());
        }
        
        if (param.getBeginModifyDate() != null && param.getEndModifyDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginModifyDate())
                   .whereLe(param.getBatchField(), param.getEndModifyDate());
        } else if (param.getBeginModifyDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginModifyDate());
        } else if (param.getEndModifyDate() != null) {
            builder.whereLe(param.getBatchField(), param.getEndModifyDate());
        }
        
        return builder.buildCountQuery();
    }

    /**
     * 执行查询并处理结果
     *
     * @param connection SOAP连接
     * @param param      查询参数
     * @param fieldList  字段列表
     * @return 处理的数据条数
     */
    private int executeQueryAndProcessData(IPartnerV1Connection connection, DataiSyncParam param, List<String> fieldList) {
        int totalCount = 0;
        JSONArray objects = null;
        String maxId = null;
        Date lastDate = null;

        try {
            DescribeSObjectResult describeSObject = connection.describeSObject(param.getApi());
            Field[] dsrFields = describeSObject.getFields();

            while (true) {
                DataiSyncParam queryParam = new DataiSyncParam();
                queryParam.setApi(param.getApi());
                queryParam.setSelect(param.getSelect());
                queryParam.setBatchField(param.getBatchField());
                queryParam.setIdField(param.getIdField());
                queryParam.setIsDeleted(param.getIsDeleted());
                
                queryParam.setBeginDate(param.getBeginDate());
                queryParam.setEndDate(param.getEndDate());
                queryParam.setLastDate(lastDate);
                queryParam.setMaxId(maxId);
                
                String query = buildDynamicQuery(queryParam);
                log.info("执行查询SQL: {}", query);
                QueryResult result = connection.queryAll(query);

                if (result.getRecords() != null && result.getRecords().length > 0) {
                    objects = ConvertUtil.toJsonArray(result.getRecords(), dsrFields);
                    Date maxDate = objects.getJSONObject(objects.size() - 1).getDate(param.getBatchField());
                    Optional<String> maxIdOptional = objects.stream()
                            .map(t -> (JSONObject) t)
                            .filter(t -> maxDate.equals(t.getDate(param.getBatchField())))
                            .map(t -> t.getString("Id"))
                            .max(String::compareTo);
                    maxId = maxIdOptional.orElse(null);
                    lastDate = maxDate;

                    totalCount += processQueryResult(param.getApi(), result.getRecords(), objects);
                    log.info("已处理 {} 条记录", totalCount);
                }

                if (result.isDone() || result.getRecords() == null || result.getRecords().length == 0) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("查询处理数据时发生异常，对象API: {}", param.getApi(), e);
        }
        return totalCount;
    }

    /**
     * 构建动态查询语句
     *
     * @param param 查询参数
     * @return SOQL查询语句
     */
    private String buildDynamicQuery(DataiSyncParam param) {
        SoqlBuilder builder = new SoqlBuilder();
        
        String[] selectFields = param.getSelect().split(",");
        builder.select(selectFields)
               .from(param.getApi());
        
        if (param.getIsDeleted() != null && param.getIsDeleted()) {
            builder.where("IsDeleted = false");
        }
        
        if (param.getBeginDate() != null && param.getEndDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginDate())
                   .whereLe(param.getBatchField(), param.getEndDate());
        } else if (param.getBeginDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginDate());
        } else if (param.getEndDate() != null) {
            builder.whereLe(param.getBatchField(), param.getEndDate());
        }
        
        if (param.getBeginCreateDate() != null && param.getEndCreateDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginCreateDate())
                   .whereLe(param.getBatchField(), param.getEndCreateDate());
        } else if (param.getBeginCreateDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginCreateDate());
        } else if (param.getEndCreateDate() != null) {
            builder.whereLe(param.getBatchField(), param.getEndCreateDate());
        }

        if (param.getLastDate() != null) {
            builder.whereLe(param.getBatchField(), param.getLastDate());
        }
        
        if (param.getBeginModifyDate() != null && param.getEndModifyDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginModifyDate())
                   .whereLe(param.getBatchField(), param.getEndModifyDate());
        } else if (param.getBeginModifyDate() != null) {
            builder.whereGe(param.getBatchField(), param.getBeginModifyDate());
        } else if (param.getEndModifyDate() != null) {
            builder.whereLe(param.getBatchField(), param.getEndModifyDate());
        }
        
        if (StringUtils.isNotEmpty(param.getMaxId())) {
            builder.whereGt(param.getIdField(), param.getMaxId());
        }
        
        if (param.getLimit() != null && param.getLimit() > 0) {
            builder.limit(param.getLimit());
        }

        
        return builder.build();
    }

    /**
     * 处理查询结果
     *
     * @param api       API名称

     * @return 处理的数据条数
     */
    private int processQueryResult(String api, SObject[] records, JSONArray objects) {
        int count = 0;
        
        log.info("处理API {} 的查询结果，共 {} 条记录", api, records.length);

        boolean isPartitioned = checkIfTablePartitioned(api);
        String batchField = null;
        if (isPartitioned) {
            batchField = integrationFieldService.getDateField(api);
        }

        if (objects == null || objects.isEmpty()) {
            log.info("API {} 没有需要处理的数据", api);
            return 0;
        }

        try {
            List<String> ids = Arrays.stream(records).map(SObject::getId).collect(Collectors.toList());
            List<String> existsIds = customMapper.getIds(api, ids);
            
            String partitionName = null;
            if (isPartitioned && batchField != null) {
                partitionName = buildPartitionName(batchField, objects);
            }

            List<Map<String, Object>> insertMaps = new ArrayList<>();
            List<Map<String, Object>> updateMaps = new ArrayList<>();
            List<String> updateIds = new ArrayList<>();

            for (int i = 0; i < objects.size(); i++) {
                JSONObject jsonObject = objects.getJSONObject(i);
                String id = jsonObject.getString("Id");
                
                Map<String, Object> recordMap = new HashMap<>();
                for (String key : jsonObject.keySet()) {
                    recordMap.put(key, jsonObject.get(key));
                }

                if (existsIds.contains(id)) {
                    updateMaps.add(recordMap);
                    updateIds.add(id);
                } else {
                    insertMaps.add(recordMap);
                }
            }

            if (!insertMaps.isEmpty()) {
                List<String> keys = new ArrayList<>(insertMaps.get(0).keySet());
                List<Collection<Object>> values = new ArrayList<>();
                
                for (Map<String, Object> recordMap : insertMaps) {
                    List<Object> rowValues = new ArrayList<>();
                    for (String key : keys) {
                        rowValues.add(recordMap.get(key));
                    }
                    values.add(rowValues);
                }

                if (isPartitioned && partitionName != null) {
                    customMapper.saveBatchToPartition(api, partitionName, keys, values);
                    log.info("成功插入 {} 条记录到分区表 {} 的分区 {}", values.size(), api, partitionName);
                } else {
                    customMapper.saveBatch(api, keys, values);
                    log.info("成功插入 {} 条记录到表 {}", values.size(), api);
                }
                count += values.size();
            }

            if (!updateMaps.isEmpty()) {
                for (int i = 0; i < updateMaps.size(); i++) {
                    Map<String, Object> recordMap = updateMaps.get(i);
                    String id = updateIds.get(i);
                    
                    List<Map<String, Object>> maps = new ArrayList<>();
                    for (Map.Entry<String, Object> entry : recordMap.entrySet()) {
                        Map<String, Object> paramMap = new HashMap<>();
                        paramMap.put("key", entry.getKey());
                        paramMap.put("value", entry.getValue());
                        maps.add(paramMap);
                    }

                    if (isPartitioned && partitionName != null) {
                        customMapper.updateByIdFromPartition(api, partitionName, maps, id);
                    } else {
                        customMapper.updateById(api, maps, id);
                    }
                }
                log.info("成功更新 {} 条记录到表 {}", updateMaps.size(), api);
                count += updateMaps.size();
            }
            
        } catch (Exception e) {
            log.error("处理API {} 的查询结果时发生异常", api, e);
            throw new RuntimeException("处理查询结果失败: " + e.getMessage(), e);
        }

        return count;
    }



    /**
     * 检查表是否已分区
     *
     * @param tableName 表名
     * @return 是否已分区
     */
    private boolean checkIfTablePartitioned(String tableName) {
        Boolean isPartitioned = customMapper.isPartitioned(tableName);
        return (isPartitioned != null) ? isPartitioned : false;
    }

    /**
     * 根据批次字段和数据构建分区名
     *
     * @param batchField 批次字段名
     * @param objects 数据对象数组
     * @return 分区名（如p2025）
     */
    private String buildPartitionName(String batchField, JSONArray objects) {
        String partitionName = "p_default";
        
        if (StringUtils.isNotEmpty(batchField) && !objects.isEmpty()) {
            JSONObject firstRecord = objects.getJSONObject(0);
            Object dateValue = firstRecord.get(batchField);
            
            if (dateValue instanceof Date) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime((Date) dateValue);
                int year = calendar.get(Calendar.YEAR);
                partitionName = "p" + year;
            }
        }
        
        return partitionName;
    }

    /**
     * 获取所有批次统计信息
     *
     * @return 所有批次统计信息
     */
    @Override
    public Map<String, Object> getAllBatchStatistics() {
        Map<String, Object> statistics = new HashMap<>();

        try {
            log.info("开始获取所有批次统计信息");
            
            // 查询所有批次
            List<DataiIntegrationBatch> batches = selectDataiIntegrationBatchList(new DataiIntegrationBatch());
            
            if (batches.isEmpty()) {
                log.warn("未找到批次数据");
                statistics.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                statistics.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_NO_BATCH_DATA_FOUND);
                return statistics;
            }
            
            int totalCount = batches.size();
            int successCount = 0;
            int failedCount = 0;
            int totalSfNum = 0;
            int totalDbNum = 0;
            long totalCost = 0;
            int historyCount = 0;
            
            // 统计批次基本信息
            for (DataiIntegrationBatch batch : batches) {
                if (Boolean.TRUE.equals(batch.getSyncStatus())) {
                    successCount++;
                } else {
                    failedCount++;
                }
                
                if (batch.getSfNum() != null) {
                    totalSfNum += batch.getSfNum();
                }
                
                if (batch.getDbNum() != null) {
                    totalDbNum += batch.getDbNum();
                }
            }
            
            // 查询所有批次历史记录，用于计算更详细的统计信息
            DataiIntegrationBatchHistory queryHistory = new DataiIntegrationBatchHistory();
            List<DataiIntegrationBatchHistory> histories = batchHistoryService.selectDataiIntegrationBatchHistoryList(queryHistory);
            
            for (DataiIntegrationBatchHistory history : histories) {
                historyCount++;
                if (history.getCost() != null) {
                    totalCost += history.getCost();
                }
            }
            
            double successRate = totalCount > 0 ? (double) successCount / totalCount * 100 : 0;
            double avgSfNum = totalCount > 0 ? (double) totalSfNum / totalCount : 0;
            double avgDbNum = totalCount > 0 ? (double) totalDbNum / totalCount : 0;
            long avgCost = historyCount > 0 ? totalCost / historyCount : 0;
            
            // 构建统计结果
            statistics.put(SalesforceConstants.RESULT_KEY_SUCCESS, true);
            statistics.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_GET_ALL_STATISTICS_SUCCESS);
            
            Map<String, Object> data = new HashMap<>();
            data.put(SalesforceConstants.RESULT_KEY_TOTAL_COUNT_STAT, totalCount);
            data.put(SalesforceConstants.RESULT_KEY_SUCCESS_COUNT_STAT, successCount);
            data.put(SalesforceConstants.RESULT_KEY_FAILED_COUNT_STAT, failedCount);
            data.put(SalesforceConstants.RESULT_KEY_SUCCESS_RATE, Math.round(successRate * 100.0) / 100.0);
            data.put(SalesforceConstants.RESULT_KEY_TOTAL_SF_NUM, totalSfNum);
            data.put(SalesforceConstants.RESULT_KEY_TOTAL_DB_NUM, totalDbNum);
            data.put(SalesforceConstants.RESULT_KEY_AVG_SF_NUM, Math.round(avgSfNum * 100.0) / 100.0);
            data.put(SalesforceConstants.RESULT_KEY_AVG_DB_NUM, Math.round(avgDbNum * 100.0) / 100.0);
            data.put(SalesforceConstants.RESULT_KEY_TOTAL_HISTORY_COUNT, historyCount);
            data.put(SalesforceConstants.RESULT_KEY_TOTAL_COST, totalCost);
            data.put(SalesforceConstants.RESULT_KEY_AVG_COST, avgCost);
            
            Map<String, Object> syncTypeStats = new HashMap<>();
            Map<String, Integer> syncTypeCount = new HashMap<>();
            
            for (DataiIntegrationBatch batch : batches) {
                String syncType = batch.getSyncType();
                if (syncType != null) {
                    syncTypeCount.put(syncType, syncTypeCount.getOrDefault(syncType, 0) + 1);
                }
            }
            
            syncTypeStats.put(SalesforceConstants.RESULT_KEY_TYPE_COUNT, syncTypeCount);
            data.put(SalesforceConstants.RESULT_KEY_SYNC_TYPE_STATS, syncTypeStats);
            
            statistics.put(SalesforceConstants.RESULT_KEY_DATA, data);
            
            log.info("获取所有批次统计信息成功，总批次数: {}, 成功批次数: {}, 失败批次数: {}, 成功率: {:.2f}%", 
                    totalCount, successCount, failedCount, successRate);
        } catch (Exception e) {
            log.error("获取所有批次统计信息时发生异常", e);
            statistics.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            statistics.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_GET_ALL_STATISTICS_FAILED + e.getMessage());
        }

        return statistics;
    }

    @Override
    public Map<String, Object> insertBatchDataToTarget(Integer id, String targetOrgType) {
        Map<String, Object> result = new HashMap<>();
        long startTime = System.currentTimeMillis();
        log.info(SalesforceConstants.LOG_START_INSERT_BATCH, id, targetOrgType);

        if (id == null) {
            log.error(SalesforceConstants.LOG_BATCH_ID_NULL);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_ID_NULL);
            return result;
        }

        if (targetOrgType == null || targetOrgType.trim().isEmpty()) {
            log.error(SalesforceConstants.LOG_TARGET_ORG_TYPE_NULL);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TARGET_ORG_TYPE_NULL);
            return result;
        }

        DataiIntegrationBatch batch = selectDataiIntegrationBatchById(id);
        if (batch == null) {
            log.error(SalesforceConstants.LOG_BATCH_NOT_EXIST, id);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_NOT_EXIST);
            return result;
        }

        String objectApi = batch.getApi();
        if (objectApi == null || objectApi.trim().isEmpty()) {
            log.error(SalesforceConstants.LOG_BATCH_API_NULL, id);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_API_NULL);
            return result;
        }

        String tableName = objectApi.trim();
        if (customMapper.checkTable(tableName) == null) {
            log.error(SalesforceConstants.LOG_TABLE_NOT_EXIST, tableName);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TABLE_NOT_EXIST + tableName);
            return result;
        }

        log.info(SalesforceConstants.LOG_PREPARE_INSERT_BATCH, id, objectApi);

        IPartnerV1Connection targetConnection = null;
        try {
            targetConnection = soapConnectionFactory.getConnection(targetOrgType);
            if (targetConnection == null) {
                log.error(SalesforceConstants.LOG_TARGET_CONNECTION_NULL, targetOrgType);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TARGET_CONNECTION_NULL);
                return result;
            }

            DescribeSObjectResult objDetail = targetConnection.describeSObject(objectApi);
            if (objDetail == null) {
                log.error(SalesforceConstants.LOG_TARGET_OBJECT_NOT_EXIST, objectApi);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TARGET_OBJECT_NOT_EXIST + objectApi);
                return result;
            }

            String batchField = batch.getBatchField();
            String whereClause = "";
            if (batchField != null && !batchField.trim().isEmpty()) {
                whereClause = "WHERE " + batchField.trim();
            }

            log.info(SalesforceConstants.LOG_QUERY_BATCH_DATA, tableName, whereClause);
            List<Map<String, Object>> dataList = customMapper.list("*", tableName, whereClause);

            if (dataList == null || dataList.isEmpty()) {
                log.warn(SalesforceConstants.LOG_NO_BATCH_DATA, tableName, whereClause);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_NO_BATCH_DATA);
                return result;
            }

            log.info(SalesforceConstants.LOG_FOUND_BATCH_DATA, dataList.size());

            int successCount = 0;
            int failureCount = 0;
            List<Map<String, Object>> failedRecords = new ArrayList<>();

            Field[] dsrFields = objDetail.getFields();

            DataiIntegrationField queryField = new DataiIntegrationField();
            queryField.setApi(objectApi);
            List<DataiIntegrationField> fieldList = integrationFieldService.selectDataiIntegrationFieldList(queryField);

            int totalCount = dataList.size();
            int num = totalCount % SalesforceConstants.LARGE_BATCH_SIZE == 0 ? totalCount / SalesforceConstants.LARGE_BATCH_SIZE : (totalCount / SalesforceConstants.LARGE_BATCH_SIZE) + 1;

            log.info(SalesforceConstants.LOG_TOTAL_INSERT_DATA, totalCount, num, objectApi);

            for (int z = 0; z < num; z++) {
                int startIndex = z * SalesforceConstants.LARGE_BATCH_SIZE;
                int endIndex = Math.min(startIndex + SalesforceConstants.LARGE_BATCH_SIZE, totalCount);
                List<Map<String, Object>> mapsList = dataList.subList(startIndex, endIndex);

                int size = mapsList.size();
                int page = size % SalesforceConstants.SMALL_BATCH_SIZE == 0 ? size / SalesforceConstants.SMALL_BATCH_SIZE : (size / SalesforceConstants.SMALL_BATCH_SIZE) + 1;

                log.info(SalesforceConstants.LOG_CURRENT_BATCH_INSERT_DATA, totalCount, z, objectApi);

                for (int i = 0; i < page; i++) {
                    int batchStartIndex = SalesforceConstants.SMALL_BATCH_SIZE * i;
                    int batchEndIndex = Math.min(batchStartIndex + SalesforceConstants.SMALL_BATCH_SIZE, size);
                    if (batchStartIndex >= batchEndIndex) {
                        break;
                    }
                    List<Map<String, Object>> data = mapsList.subList(batchStartIndex, batchEndIndex);
                    int sized = data.size();

                    SObject[] accounts = new SObject[sized];
                    String[] ids = new String[sized];
                    List<String> errorMessageList = new ArrayList<>();

                    try {
                        Map<String, Map<String, String>> referenceCache = new HashMap<>();
                        
                        for (int j = 0; j < sized; j++) {
                            Map<String, Object> localData = data.get(j);
                            String message = null;

                            for (DataiIntegrationField dataField : fieldList) {
                                String fieldMessage = processFieldForInsert(localData, dataField, referenceCache, objectApi);
                                if (fieldMessage != null) {
                                    message = fieldMessage;
                                    break;
                                }
                            }

                            if (message != null) {
                                errorMessageList.add(message);
                                failureCount++;
                                Map<String, Object> failedRecord = new HashMap<>();
                                failedRecord.put("index", startIndex + batchStartIndex + j);
                                failedRecord.put("localId", localData.get("id"));
                                failedRecord.put("reason", message);
                                failedRecords.add(failedRecord);
                                ids[j] = localData.get("id").toString();
                                continue;
                            }

                            SObject account = buildSObjectFromLocalData(localData, fieldList, objectApi, referenceCache);
                            ids[j] = localData.get("id").toString();
                            accounts[j] = account;
                        }

                        SaveResult[] saveResults = targetConnection.create(accounts);
                        for (int j = 0; j < saveResults.length; j++) {
                            if (saveResults[j].isSuccess()) {
                                List<Map<String, Object>> maps = new ArrayList<>();
                                Map<String, Object> m = new HashMap<>();
                                m.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_NEW_ID);
                                m.put(SalesforceConstants.UPDATE_MAP_VALUE, saveResults[j].getId());
                                maps.add(m);

                                Map<String, Object> isInsertMap = new HashMap<>();
                                isInsertMap.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_IS_INSERT);
                                isInsertMap.put(SalesforceConstants.UPDATE_MAP_VALUE, SalesforceConstants.SYNC_STATUS_SYNCED);
                                maps.add(isInsertMap);

                                customMapper.updateById(tableName, maps, ids[j]);
                                successCount++;
                                log.debug(SalesforceConstants.LOG_RECORD_INSERT_SUCCESS, ids[j], saveResults[j].getId());
                            } else {
                                String errorMsg = saveResults[j].getErrors()[0].getMessage();
                                log.error(SalesforceConstants.LOG_RECORD_INSERT_FAILED, ids[j], errorMsg);
                                failureCount++;

                                List<Map<String, Object>> maps = new ArrayList<>();
                                Map<String, Object> linkMap1 = new HashMap<>();
                                linkMap1.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_ERROR_MESSAGE);
                                linkMap1.put(SalesforceConstants.UPDATE_MAP_VALUE, JSON.toJSONString(saveResults[j].getErrors()));
                                maps.add(linkMap1);
                                customMapper.updateById(tableName, maps, ids[j]);

                                Map<String, Object> failedRecord = new HashMap<>();
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_INDEX, startIndex + batchStartIndex + j);
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_LOCAL_ID, ids[j]);
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_REASON, errorMsg);
                                failedRecords.add(failedRecord);
                            }
                        }

                        if ((z * 50 + i + 1) % SalesforceConstants.LOG_OUTPUT_INTERVAL == 0) {
                            log.info(SalesforceConstants.LOG_INSERTED_RECORDS, startIndex + batchEndIndex, totalCount);
                        }

                        try {
                            TimeUnit.MILLISECONDS.sleep(SalesforceConstants.BATCH_SLEEP_MS);
                        } catch (InterruptedException e) {
                            log.warn(SalesforceConstants.LOG_THREAD_SLEEP_INTERRUPTED, e);
                            Thread.currentThread().interrupt();
                        }
                    } catch (Exception e) {
                        log.error(SalesforceConstants.LOG_INSERT_BATCH_EXCEPTION, z, i, e);
                        for (int j = 0; j < sized; j++) {
                            failureCount++;
                            Map<String, Object> failedRecord = new HashMap<>();
                            failedRecord.put("index", startIndex + batchStartIndex + j);
                            failedRecord.put("localId", data.get(j).get("id"));
                            failedRecord.put("reason", e.getMessage());
                            failedRecords.add(failedRecord);
                        }
                    }
                }
            }

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, true);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_INSERT_COMPLETE);
            result.put(SalesforceConstants.RESULT_KEY_BATCH_ID, id);
            result.put(SalesforceConstants.RESULT_KEY_API, objectApi);
            result.put(SalesforceConstants.RESULT_KEY_LABEL, batch.getLabel());
            result.put(SalesforceConstants.RESULT_KEY_TARGET_ORG_TYPE, targetOrgType);
            result.put(SalesforceConstants.RESULT_KEY_TOTAL_COUNT, totalCount);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS_COUNT, successCount);
            result.put(SalesforceConstants.RESULT_KEY_FAILURE_COUNT, failureCount);
            result.put(SalesforceConstants.RESULT_KEY_DURATION, duration);
            result.put(SalesforceConstants.RESULT_KEY_FAILED_RECORDS, failedRecords);

            log.info(SalesforceConstants.LOG_BATCH_INSERT_COMPLETE, id, objectApi, totalCount, successCount, failureCount, duration);

        } catch (Exception e) {
            log.error(SalesforceConstants.LOG_BATCH_INSERT_FAILED, id, e);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_INSERT_FAILED + e.getMessage());
        }

        return result;
    }

    public Map<String, Object> updateBatchDataToTarget(Integer id, String targetOrgType) {
        Map<String, Object> result = new HashMap<>();
        long startTime = System.currentTimeMillis();

        log.info(SalesforceConstants.LOG_START_UPDATE_BATCH, id, targetOrgType);

        if (id == null) {
            log.error(SalesforceConstants.LOG_BATCH_ID_NULL);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_ID_NULL);
            return result;
        }

        if (targetOrgType == null || targetOrgType.trim().isEmpty()) {
            log.error(SalesforceConstants.LOG_TARGET_ORG_TYPE_NULL);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TARGET_ORG_TYPE_NULL);
            return result;
        }

        DataiIntegrationBatch batch = selectDataiIntegrationBatchById(id);
        if (batch == null) {
            log.error(SalesforceConstants.LOG_BATCH_NOT_EXIST, id);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_NOT_EXIST);
            return result;
        }

        String objectApi = batch.getApi();
        if (objectApi == null || objectApi.trim().isEmpty()) {
            log.error(SalesforceConstants.LOG_BATCH_API_NULL, id);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_API_NULL);
            return result;
        }

        String tableName = objectApi.trim();
        if (customMapper.checkTable(tableName) == null) {
            log.error(SalesforceConstants.LOG_TABLE_NOT_EXIST, tableName);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TABLE_NOT_EXIST + tableName);
            return result;
        }

        log.info(SalesforceConstants.LOG_PREPARE_UPDATE_BATCH, id, objectApi);

        IPartnerV1Connection targetConnection = null;
        try {
            targetConnection = soapConnectionFactory.getConnection(targetOrgType);
            if (targetConnection == null) {
                log.error(SalesforceConstants.LOG_TARGET_CONNECTION_NULL, targetOrgType);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TARGET_CONNECTION_NULL);
                return result;
            }

            DescribeSObjectResult objDetail = targetConnection.describeSObject(objectApi);
            if (objDetail == null) {
                log.error(SalesforceConstants.LOG_TARGET_OBJECT_NOT_EXIST, objectApi);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_TARGET_OBJECT_NOT_EXIST + objectApi);
                return result;
            }

            String batchField = batch.getBatchField();
            String whereClause = "";
            if (batchField != null && !batchField.trim().isEmpty()) {
                whereClause = "WHERE " + batchField.trim();
            }

            whereClause = (whereClause.isEmpty() ? "WHERE " : whereClause + " AND ") + SalesforceConstants.DB_FIELD_NEW_ID + " is not null AND " + SalesforceConstants.DB_FIELD_IS_UPDATE + " = " + SalesforceConstants.SYNC_STATUS_NOT_SYNCED;

            log.info(SalesforceConstants.LOG_QUERY_BATCH_DATA, tableName, whereClause);
            List<Map<String, Object>> dataList = customMapper.list("*", tableName, whereClause);

            if (dataList == null || dataList.isEmpty()) {
                log.warn(SalesforceConstants.LOG_NO_BATCH_DATA, tableName, whereClause);
                result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
                result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_NO_BATCH_DATA);
                return result;
            }

            log.info(SalesforceConstants.LOG_FOUND_BATCH_DATA_UPDATE, dataList.size());

            Field[] dsrFields = objDetail.getFields();

            DataiIntegrationField queryField = new DataiIntegrationField();
            queryField.setApi(objectApi);
            List<DataiIntegrationField> fieldList = integrationFieldService.selectDataiIntegrationFieldList(queryField);

            int totalCount = dataList.size();
            int num = totalCount % SalesforceConstants.LARGE_BATCH_SIZE == 0 ? totalCount / SalesforceConstants.LARGE_BATCH_SIZE : (totalCount / SalesforceConstants.LARGE_BATCH_SIZE) + 1;

            log.info(SalesforceConstants.LOG_TOTAL_UPDATE_DATA, totalCount, num, objectApi);

            int successCount = 0;
            int failureCount = 0;
            List<Map<String, Object>> failedRecords = new ArrayList<>();

            for (int z = 0; z < num; z++) {
                int startIndex = z * SalesforceConstants.LARGE_BATCH_SIZE;
                int endIndex = Math.min(startIndex + SalesforceConstants.LARGE_BATCH_SIZE, totalCount);
                List<Map<String, Object>> mapsList = dataList.subList(startIndex, endIndex);

                int size = mapsList.size();
                int page = size % SalesforceConstants.SMALL_BATCH_SIZE == 0 ? size / SalesforceConstants.SMALL_BATCH_SIZE : (size / SalesforceConstants.SMALL_BATCH_SIZE) + 1;

                log.info(SalesforceConstants.LOG_CURRENT_BATCH_UPDATE_DATA, totalCount, z, objectApi);

                for (int i = 0; i < page; i++) {
                    int batchStartIndex = SalesforceConstants.SMALL_BATCH_SIZE * i;
                    int batchEndIndex = Math.min(batchStartIndex + SalesforceConstants.SMALL_BATCH_SIZE, size);
                    if (batchStartIndex >= batchEndIndex) {
                        break;
                    }
                    List<Map<String, Object>> data = mapsList.subList(batchStartIndex, batchEndIndex);
                    int sized = data.size();

                    SObject[] accounts = new SObject[sized];
                    String[] newIds = new String[sized];

                    try {
                        Map<String, Map<String, String>> referenceCache = new HashMap<>();
                        
                        for (int j = 0; j < sized; j++) {
                            Map<String, Object> localData = data.get(j);
                            String message = null;
                            List<String> fieldsToNull = new ArrayList<>();

                            for (DataiIntegrationField dataField : fieldList) {
                                String fieldMessage = processFieldForUpdate(localData, dataField, referenceCache, objectApi, fieldsToNull);
                                if (fieldMessage != null) {
                                    message = fieldMessage;
                                    break;
                                }
                            }

                            if (message != null) {
                                failureCount++;
                                Map<String, Object> failedRecord = new HashMap<>();
                                failedRecord.put("index", startIndex + batchStartIndex + j);
                                failedRecord.put("localId", localData.get("id"));
                                failedRecord.put("newId", localData.get("new_id"));
                                failedRecord.put("reason", message);
                                failedRecords.add(failedRecord);
                                newIds[j] = String.valueOf(localData.get("new_id"));
                                continue;
                            }

                            SObject account = buildSObjectFromLocalDataForUpdate(localData, fieldList, objectApi, referenceCache, fieldsToNull);
                            newIds[j] = String.valueOf(localData.get("new_id"));
                            accounts[j] = account;
                        }

                        SaveResult[] saveResults = targetConnection.update(accounts);
                        for (int j = 0; j < saveResults.length; j++) {
                            if (saveResults[j].isSuccess()) {
                                List<Map<String, Object>> maps = new ArrayList<>();
                                Map<String, Object> linkMap1 = new HashMap<>();
                                linkMap1.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_IS_UPDATE);
                                linkMap1.put(SalesforceConstants.UPDATE_MAP_VALUE, SalesforceConstants.SYNC_STATUS_SYNCED);
                                maps.add(linkMap1);
                                Map<String, Object> linkMap2 = new HashMap<>();
                                linkMap2.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_ERROR_MESSAGE);
                                linkMap2.put(SalesforceConstants.UPDATE_MAP_VALUE, null);
                                maps.add(linkMap2);
                                customMapper.updateById(tableName, maps, data.get(j).get(SalesforceConstants.DB_FIELD_ID).toString());
                                successCount++;
                                log.debug(SalesforceConstants.LOG_RECORD_UPDATE_SUCCESS, data.get(j).get(SalesforceConstants.DB_FIELD_ID), newIds[j]);
                            } else {
                                String errorMsg = saveResults[j].getErrors()[0].getMessage();
                                log.error(SalesforceConstants.LOG_RECORD_UPDATE_FAILED, data.get(j).get(SalesforceConstants.DB_FIELD_ID), newIds[j], errorMsg);
                                failureCount++;

                                List<Map<String, Object>> maps = new ArrayList<>();
                                Map<String, Object> linkMap1 = new HashMap<>();
                                linkMap1.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_IS_UPDATE);
                                linkMap1.put(SalesforceConstants.UPDATE_MAP_VALUE, SalesforceConstants.SYNC_STATUS_FAILED);
                                maps.add(linkMap1);
                                Map<String, Object> linkMap2 = new HashMap<>();
                                linkMap2.put(SalesforceConstants.UPDATE_MAP_KEY, SalesforceConstants.DB_FIELD_ERROR_MESSAGE);
                                linkMap2.put(SalesforceConstants.UPDATE_MAP_VALUE, JSON.toJSONString(saveResults[j].getErrors()));
                                maps.add(linkMap2);
                                customMapper.updateById(tableName, maps, data.get(j).get(SalesforceConstants.DB_FIELD_ID).toString());

                                Map<String, Object> failedRecord = new HashMap<>();
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_INDEX, startIndex + batchStartIndex + j);
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_LOCAL_ID, data.get(j).get(SalesforceConstants.DB_FIELD_ID));
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_NEW_ID, newIds[j]);
                                failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_REASON, errorMsg);
                                failedRecords.add(failedRecord);
                            }
                        }

                        if ((z * 50 + i + 1) % SalesforceConstants.LOG_OUTPUT_INTERVAL == 0) {
                            log.info(SalesforceConstants.LOG_UPDATED_RECORDS, startIndex + batchEndIndex, totalCount);
                        }

                        try {
                            TimeUnit.MILLISECONDS.sleep(SalesforceConstants.BATCH_SLEEP_MS);
                        } catch (InterruptedException e) {
                            log.warn(SalesforceConstants.LOG_THREAD_SLEEP_INTERRUPTED, e);
                            Thread.currentThread().interrupt();
                        }
                    } catch (Exception e) {
                        log.error(SalesforceConstants.LOG_UPDATE_BATCH_EXCEPTION, z, i, e);
                        for (int j = 0; j < sized; j++) {
                            failureCount++;
                            Map<String, Object> failedRecord = new HashMap<>();
                            failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_INDEX, startIndex + batchStartIndex + j);
                            failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_LOCAL_ID, data.get(j).get(SalesforceConstants.DB_FIELD_ID));
                            failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_NEW_ID, newIds[j]);
                            failedRecord.put(SalesforceConstants.FAILED_RECORD_KEY_REASON, e.getMessage());
                            failedRecords.add(failedRecord);
                        }
                    }
                }
            }

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, true);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_UPDATE_COMPLETE);
            result.put(SalesforceConstants.RESULT_KEY_BATCH_ID, id);
            result.put(SalesforceConstants.RESULT_KEY_API, objectApi);
            result.put(SalesforceConstants.RESULT_KEY_LABEL, batch.getLabel());
            result.put(SalesforceConstants.RESULT_KEY_TARGET_ORG_TYPE, targetOrgType);
            result.put(SalesforceConstants.RESULT_KEY_TOTAL_COUNT, totalCount);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS_COUNT, successCount);
            result.put(SalesforceConstants.RESULT_KEY_FAILURE_COUNT, failureCount);
            result.put(SalesforceConstants.RESULT_KEY_DURATION, duration);
            result.put(SalesforceConstants.RESULT_KEY_FAILED_RECORDS, failedRecords);

            log.info(SalesforceConstants.LOG_BATCH_UPDATE_COMPLETE, id, objectApi, totalCount, successCount, failureCount, duration);

        } catch (Exception e) {
            log.error(SalesforceConstants.LOG_BATCH_UPDATE_FAILED, id, e);
            result.put(SalesforceConstants.RESULT_KEY_SUCCESS, false);
            result.put(SalesforceConstants.RESULT_KEY_MESSAGE, SalesforceConstants.ERROR_BATCH_UPDATE_FAILED + e.getMessage());
        }

        return result;
    }

    private String resolveReferenceToObject(String referenceTo, Map<String, Object> localData, String polymorphicField) {
        if (referenceTo == null) {
            return null;
        }
        
        String referenceToObject = referenceTo;
        if (referenceTo.contains(",User") || referenceTo.contains("User,")) {
            referenceToObject = "User";
        }
        
        if (StringUtils.isNotBlank(polymorphicField)) {
            Object polymorphicValue = localData.get(polymorphicField);
            if (polymorphicValue != null) {
                referenceToObject = polymorphicValue.toString();
            }
        }
        
        return referenceToObject;
    }

    private Map<String, String> batchQueryNewIds(List<String> localIds, String referenceToObject) {
        Map<String, String> result = new HashMap<>();
        if (localIds == null || localIds.isEmpty() || referenceToObject == null) {
            return result;
        }
        
        try {
            String idList = localIds.stream()
                .map(id -> "'" + id + "'")
                .collect(Collectors.joining(","));
            
            String sql = "SELECT " + SalesforceConstants.DB_FIELD_ID + ", " + SalesforceConstants.DB_FIELD_NEW_ID + " FROM " + referenceToObject + " WHERE " + SalesforceConstants.DB_FIELD_ID + " IN (" + idList + ")";
            List<Map<String, Object>> results = customMapper.list("*", referenceToObject, sql);
            
            for (Map<String, Object> row : results) {
                String id = (String) row.get(SalesforceConstants.DB_FIELD_ID);
                String newId = (String) row.get(SalesforceConstants.DB_FIELD_NEW_ID);
                if (id != null && newId != null) {
                    result.put(id, newId);
                }
            }
        } catch (Exception e) {
            log.warn(SalesforceConstants.LOG_BATCH_QUERY_NEW_ID_FAILED, referenceToObject, e.getMessage());
        }
        
        return result;
    }

    private String processFieldForInsert(Map<String, Object> localData, DataiIntegrationField dataField, 
                                         Map<String, Map<String, String>> referenceCache, String objectApi) {
        String field = dataField.getField();
        String referenceTo = dataField.getReferenceTo();
        String sfType = dataField.getSoapType();
        String polymorphicField = dataField.getPolymorphicForeignField();
        
        Object value = localData.get(field);
        if (value == null) {
            return null;
        }
        
        String valueStr = String.valueOf(value);
        
        if ("reference".equalsIgnoreCase(sfType) && !"null".equals(valueStr) && StringUtils.isNotEmpty(valueStr)) {
            String referenceToObject = resolveReferenceToObject(referenceTo, localData, polymorphicField);
            if (referenceToObject == null) {
                return SalesforceConstants.LOG_REFERENCE_OBJECT_TYPE_NULL;
            }
            
            Map<String, String> cache = referenceCache.computeIfAbsent(referenceToObject, k -> new HashMap<>());
            String newId = cache.get(valueStr);
            
            if (newId == null) {
                Map<String, String> batchResult = batchQueryNewIds(Collections.singletonList(valueStr), referenceToObject);
                cache.putAll(batchResult);
                newId = batchResult.get(valueStr);
            }
            
            if (newId != null) {
                localData.put(field + "_new_id", newId);
            } else {
                return "对象类型:" + objectApi + "的数据:" + localData.get(SalesforceConstants.DB_FIELD_ID) + 
                       "的引用对象:" + referenceToObject + "的数据:" + valueStr + "异常！";
            }
        } else {
            try {
                Object convertedValue = ConvertUtil.localDataToSfData(sfType, valueStr);
                localData.put(field + "_converted", convertedValue);
            } catch (Exception e) {
                log.warn(SalesforceConstants.LOG_FIELD_CONVERT_FAILED, field, valueStr, e.getMessage());
            }
        }
        
        return null;
    }

    private SObject buildSObjectFromLocalData(Map<String, Object> localData, List<DataiIntegrationField> fieldList, 
                                               String objectApi, Map<String, Map<String, String>> referenceCache) {
        SObject sObject = new SObject();
        sObject.setType(objectApi);
        
        for (DataiIntegrationField dataField : fieldList) {
            if (dataField.getIsCreateable() == null || !dataField.getIsCreateable()) {
                continue;
            }
            
            String field = dataField.getField();
            String sfType = dataField.getSoapType();
            
            Object value = localData.get(field);
            if (value == null) {
                continue;
            }
            
            String valueStr = String.valueOf(value);
            
            if ("reference".equalsIgnoreCase(sfType) && !"null".equals(valueStr) && StringUtils.isNotEmpty(valueStr)) {
                String newId = (String) localData.get(field + "_new_id");
                if (newId != null) {
                    sObject.setField(field, newId);
                }
            } else {
                Object convertedValue = localData.get(field + "_converted");
                if (convertedValue != null) {
                    sObject.setField(field, convertedValue);
                }
            }
        }
        
        return sObject;
    }

    private String processFieldForUpdate(Map<String, Object> localData, DataiIntegrationField dataField, 
                                          Map<String, Map<String, String>> referenceCache, String objectApi, 
                                          List<String> fieldsToNull) {
        String field = dataField.getField();
        String referenceTo = dataField.getReferenceTo();
        String sfType = dataField.getSoapType();
        String polymorphicField = dataField.getPolymorphicForeignField();

        if ("Id".equals(field)) {
            return null;
        }

        if (dataField.getIsUpdateable() == null || !dataField.getIsUpdateable()) {
            return null;
        }

        Object value = localData.get(field);
        String valueStr = value != null ? String.valueOf(value) : null;

        if ("reference".equalsIgnoreCase(sfType) && !"null".equals(valueStr) && StringUtils.isNotEmpty(valueStr)) {
            String referenceToObject = resolveReferenceToObject(referenceTo, localData, polymorphicField);
            if (referenceToObject == null) {
                return null;
            }

            Map<String, String> cache = referenceCache.computeIfAbsent(referenceToObject, k -> new HashMap<>());
            String newId = cache.get(valueStr);

            if (newId == null) {
                Map<String, String> batchResult = batchQueryNewIds(Collections.singletonList(valueStr), referenceToObject);
                cache.putAll(batchResult);
                newId = batchResult.get(valueStr);
            }

            if (newId != null) {
                localData.put(field + "_new_id", newId);
            } else {
                return "对象类型:" + objectApi + "的数据:" + localData.get("id") + 
                       "的引用对象:" + referenceToObject + "的数据:" + valueStr + "异常！";
            }
        } else {
            if (StringUtils.isNotBlank(sfType)) {
                if (value != null) {
                    try {
                        Object convertedValue = ConvertUtil.localDataToSfData(sfType, valueStr);
                        localData.put(field + "_converted", convertedValue);
                    } catch (Exception e) {
                        log.warn("字段值转换失败，字段: {}, 值: {}, 错误: {}", field, valueStr, e.getMessage());
                    }
                } else {
                    fieldsToNull.add(field);
                }
            }
        }

        return null;
    }

    private SObject buildSObjectFromLocalDataForUpdate(Map<String, Object> localData, List<DataiIntegrationField> fieldList, 
                                                         String objectApi, Map<String, Map<String, String>> referenceCache, 
                                                         List<String> fieldsToNull) {
        SObject sObject = new SObject();
        sObject.setType(objectApi);
        sObject.setId(String.valueOf(localData.get("new_id")));

        for (DataiIntegrationField dataField : fieldList) {
            String field = dataField.getField();
            String sfType = dataField.getSoapType();

            if ("Id".equals(field)) {
                continue;
            }

            if (dataField.getIsUpdateable() == null || !dataField.getIsUpdateable()) {
                continue;
            }

            Object value = localData.get(field);
            String valueStr = value != null ? String.valueOf(value) : null;

            if ("reference".equalsIgnoreCase(sfType) && !"null".equals(valueStr) && StringUtils.isNotEmpty(valueStr)) {
                String newId = (String) localData.get(field + "_new_id");
                if (newId != null) {
                    sObject.setField(field, newId);
                }
            } else {
                Object convertedValue = localData.get(field + "_converted");
                if (convertedValue != null) {
                    sObject.setField(field, convertedValue);
                }
            }
        }

        if (!fieldsToNull.isEmpty()) {
            String[] fieldsToNullArray = fieldsToNull.toArray(new String[0]);
            sObject.setField("fieldsToNull", fieldsToNullArray);
        }

        return sObject;
    }
}
