package com.fs.aiSipCall.service;

import com.alibaba.fastjson.JSONObject;
import com.fs.aiSipCall.RemoteCommon;
import com.fs.aiSipCall.domain.AiSipCallPhone;
import com.fs.aiSipCall.service.impl.AiSipCallPhoneServiceImpl;
import com.fs.aiSipCall.utils.SipLogUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author：peicj
 * @Description: 异步执行sip获取记录
 * @Date：2026/4/15 17:29
 */
@Service
@AllArgsConstructor
public class AsyncAddSipCallRecordService {

    private static final Logger log = SipLogUtil.createSipLogger(AsyncAddSipCallRecordService.class);

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private AiSipCallPhoneServiceImpl callPhoneServiceImpl;
    
    @Autowired
    private AiSipCallTransactionService transactionService;

    /**
     * 将字符串时间转化为long类型时间戳(毫秒)
     * @param timeStr 时间字符串,支持格式: yyyy-MM-dd HH:mm:ss
     * @return 时间戳(毫秒),转换失败返回null
     */
    private Long parseTimeToMillis(String timeStr) {
        if (StringUtils.isBlank(timeStr)) {
            return null;
        }
        try {
            LocalDateTime localDateTime = LocalDateTime.parse(timeStr.trim(), FORMATTER);
            return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        } catch (Exception e) {
            log.error("sip同步电话时间字符串转换失败: {}", timeStr, e);
            return null;
        }
    }

    /**
     * 异步拉取通话记录
     * @param startTime 字符串时间参数起始位
     * @param endTime   字符串时间参数停止位
     * @param type   哪里调用的函数
     */
    @Async("scheduledExecutorService")
    public void getAutomaticCallRecord(String startTime, String endTime,String type){
        // 默认自动外呼
        String callTypeStr = "自动外呼";
        long currentStartTime = System.currentTimeMillis();
        StringBuilder logBuilder = new StringBuilder();
        boolean hasData;
        
        try {
            // 参数校验
            if (StringUtils.isBlank(startTime) || StringUtils.isBlank(endTime)) {
                log.error("sip{}同步电话 异步任务执行:{} 失败，时间参数为空: startTime={}, endTime={}", callTypeStr,type,  startTime, endTime);
                return;
            }
            
            // 获取本地当前时间段内通话记录
            Long startMillis = parseTimeToMillis(startTime);
            Long endMillis = parseTimeToMillis(endTime);
            
            if (startMillis == null || endMillis == null) {
                log.error("sip{}同步电话 异步任务执行:{} 失败，时间格式转换失败: startTime={}, endTime={}", callTypeStr,type,  startTime, endTime);
                return;
            }
            
            String result = processAutoCallRecords(startMillis, endMillis, callTypeStr, logBuilder);
            hasData = !result.contains("本地无数据") && !result.contains("本地无有效ID");

            logBuilder.append(result);
            long costTime = System.currentTimeMillis() - currentStartTime;
            logBuilder.append(" | 总耗时:").append(costTime).append("ms");
            
            // 仅在有数据或发生错误时打印info日志，避免无数据时大量日志
            if (hasData) {
                log.info("sip{}同步电话 执行:{} 完成 | {}", callTypeStr, type, logBuilder);
            }
            //无数据不打印
//            else {
//                log.debug("sip{}同步电话 执行:{} 完成 | {}", callTypeStr, type, logBuilder);
//            }
        } catch (Exception e) {
            long costTime = System.currentTimeMillis() - currentStartTime;
            log.error("sip{}同步电话 异步任务执行:{} 异常，耗时:{}ms", callTypeStr, type, costTime, e);
        }
    }
    
    /**
     * 处理自动外呼记录
     */
    private String processAutoCallRecords(Long startMillis, Long endMillis, String callTypeStr, StringBuilder logBuilder) {
        // 获取本地当前时间段内待呼叫的自动外呼记录
        List<AiSipCallPhone> localList = callPhoneServiceImpl.selectCurrentDayCallRecords(startMillis, endMillis);
        if (CollectionUtils.isEmpty(localList)) {
            logBuilder.append("本地无数据");
            return "sip" + callTypeStr + "本地无数据，无需更新";
        }

        int localSize = localList.size();
        logBuilder.append("本地数据:").append(localSize).append("条");
        log.info("sip{}同步电话 本地数据量:{}", callTypeStr, localSize);

        // 收集本地的所有id
        List<String> localIdList = localList.stream()
                .map(AiSipCallPhone::getId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        
        if (localIdList.isEmpty()) {
            logBuilder.append(" | 本地无有效ID");
            return "sip" + callTypeStr + "本地无有效ID";
        }

        // 将本地ID按200条分批查询远程接口
        int batchSize = 200;
        List<AiSipCallPhone> allRemoteData = new ArrayList<>();
        int maxRetryCount = 3; // 最大重试次数，防止死循环

        for (int i = 0; i < localIdList.size(); i += batchSize) {
            int toIndex = Math.min(i + batchSize, localIdList.size());
            List<String> batchIds = localIdList.subList(i, toIndex);

            // 获取本批次远程数据，带重试机制
            List<AiSipCallPhone> batchRemoteList = null;
            int retryCount = 0;
            while (retryCount < maxRetryCount) {
                try {
                    batchRemoteList = fetchSinglePageRecords(batchIds, callTypeStr);
                    break; // 成功则跳出重试循环
                } catch (Exception e) {
                    retryCount++;
                    log.error("sip{}同步电话 第{}批查询异常，重试次数:{}/{}", callTypeStr, (i / batchSize + 1), retryCount, maxRetryCount, e);
                    if (retryCount >= maxRetryCount) {
                        log.error("sip{}同步电话 第{}批查询达到最大重试次数，跳过本批次", callTypeStr, (i / batchSize + 1));
                        batchRemoteList = Collections.emptyList();
                    } else {
                        try {
                            Thread.sleep(500L * retryCount); // 递增等待时间
                        } catch (InterruptedException ie) {
                            Thread.currentThread().interrupt();
                            log.error("sip{}同步电话 重试等待被中断", callTypeStr);
                            batchRemoteList = Collections.emptyList();
                            break;
                        }
                    }
                }
            }
            
            if (batchRemoteList != null && !batchRemoteList.isEmpty()) {
                allRemoteData.addAll(batchRemoteList);
            }

            // 避免频繁请求，适当休眠（最后一批不休眠）
            if (toIndex < localIdList.size()) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error("sip{}同步电话 分批查询被中断，已处理批次:{}/{}", callTypeStr, (i / batchSize + 1), (localIdList.size() + batchSize - 1) / batchSize);
                    break; // 强制退出循环
                }
            }
        }

        if (allRemoteData.isEmpty()) {
            logBuilder.append(" | 远程无数据");
            return logBuilder.toString();
        }

        int remoteSize = allRemoteData.size();
        logBuilder.append(" | 开始处理远程数据:").append(remoteSize).append("条");
        return processDataWithRetry(allRemoteData, callTypeStr, logBuilder);
    }



    /**
     * 获取数据
     * @param batchIds 查询参数
     * @return 通话记录列表
     */
    private List<AiSipCallPhone> fetchSinglePageRecords(List<String> batchIds,String callTypeStr) {
        try {
            String result = RemoteCommon.sendPost(
                    RemoteCommon.REMOTE_ADDERSS_PREFIX + RemoteCommon.QUERY_CCCALLPHONE_RECORDS_BYID_API,
                    JSONObject.toJSONString(batchIds)
            );

            if (StringUtils.isBlank(result)) {
                log.error("sip{}同步电话 查询失败：接口返回为空，请求参数数量:{}", callTypeStr, batchIds != null ? batchIds.size() : 0);
                return Collections.emptyList();
            }

            JSONObject jsonObject = JSONObject.parseObject(result);
            Integer code = jsonObject.getInteger("code");

            if (code == null || code != 0) {
                String errorMsg = jsonObject.getString("msg") != null
                        ? jsonObject.getString("msg") : "未知错误";
                log.error("sip{}同步电话 查询失败，code:{}, msg:{}, 请求参数数量:{}", callTypeStr, code, errorMsg, batchIds != null ? batchIds.size() : 0);
                return Collections.emptyList();
            }

            List<AiSipCallPhone> records;
            String data = jsonObject.getString("data");
            if(StringUtils.isNotBlank(data)){
                records = JSONObject.parseArray(data, AiSipCallPhone.class);
                log.info("sip{}同步电话 解析成功，共{}条", callTypeStr, records != null ? records.size() : 0);
                return records;
            }else{
                log.error("sip{}同步电话 解析失败：data为空，完整响应:{}", callTypeStr, result);
            }
        } catch (Exception e) {
            log.error("sip{}同步电话 查询异常，请求参数数量:{}", callTypeStr, batchIds != null ? batchIds.size() : 0, e);
        }
        return Collections.emptyList();
    }

    /**
     * 处理批量数据并统计成功失败信息（支持失败重试）
     * @param dataList 数据列表
     * @return 处理结果信息
     */
    private String processDataWithRetry(List<AiSipCallPhone> dataList, String callTypeStr, StringBuilder logBuilder) {
        int batchSize = 200;
        int totalSize = dataList.size();
        int successCount = 0;
        int failCount = 0;
        List<String> failedIds = new ArrayList<>();
        List<String> successIds = new ArrayList<>();
        int maxRetryPerRecord = 2; // 单条记录最大重试次数，防止死循环

        for (int i = 0; i < dataList.size(); i += batchSize) {
            int toIndex = Math.min(i + batchSize, dataList.size());
            List<AiSipCallPhone> batchList = dataList.subList(i, toIndex);
            int batchNum = i / batchSize + 1;

            try {
                // 批量更新
                transactionService.batchUpdateCallRecords(batchList);
                successCount += batchList.size();
                batchList.forEach(record -> {
                    if (record != null && StringUtils.isNotBlank(record.getId())) {
                        successIds.add(record.getId());
                    }
                });
            } catch (Exception e) {
                log.error("sip{}同步电话 第{}批批量更新失败，开始逐条重试，数量:{}, 错误信息:{}", 
                        callTypeStr, batchNum, batchList.size(), e.getMessage());
                
                // 逐条重试
                for (AiSipCallPhone record : batchList) {
                    if (record == null || StringUtils.isBlank(record.getId())) {
                        failCount++;
                        log.warn("sip{}同步电话 记录为空或ID为空，跳过", callTypeStr);
                        continue;
                    }
                    
                    boolean success = false;
                    int retryCount = 0;
                    while (!success && retryCount < maxRetryPerRecord) {
                        try {
                            transactionService.batchUpdateCallRecords(Collections.singletonList(record));
                            successCount++;
                            successIds.add(record.getId());
                            success = true;
                        } catch (Exception retryEx) {
                            retryCount++;
                            log.error("sip{}同步电话 记录ID:{} 更新失败，重试次数:{}/{}", 
                                    callTypeStr, record.getId(), retryCount, maxRetryPerRecord, retryEx);
                            if (retryCount >= maxRetryPerRecord) {
                                failCount++;
                                failedIds.add(record.getId());
                                log.error("sip{}同步电话 记录ID:{} 达到最大重试次数，标记为失败", callTypeStr, record.getId());
                            }
                        }
                    }
                }
            }
        }

        // 构建结果信息
        logBuilder.append(" | 处理结果:总").append(totalSize)
                .append("/成功").append(successCount)
                .append("/失败").append(failCount);

        if (!successIds.isEmpty()) {
            logBuilder.append(" | 最终成功ID数:").append(successIds.size()).append(",最终成功ID列表:").append(String.join(",", successIds));
        }

        if (!failedIds.isEmpty()) {
            logBuilder.append(" | 最终失败ID数:").append(failedIds.size()).append(",最终失败ID列表:").append(String.join(",", failedIds));
        }

        return logBuilder.toString();
    }

}
