package com.ruoyi.group.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.ibs.cmpm.domain.vo.GridCmpmVO;
import com.ruoyi.ibs.cmpm.service.GridCmpmService;
import com.ruoyi.ibs.draw.mapper.DrawGridCustUserUnbindMapper;
import com.ruoyi.ibs.grid.service.RegionGridListService;
import com.ruoyi.group.domain.dto.CustGroupMemberTemplate;
import com.ruoyi.group.domain.dto.CustGroupQueryDTO;
import com.ruoyi.group.domain.dto.GridImportDTO;
import com.ruoyi.group.domain.entity.CustGroup;
import com.ruoyi.group.domain.entity.CustGroupMember;
import com.ruoyi.group.domain.vo.CustGroupVO;
import com.ruoyi.group.mapper.CustGroupMapper;
import com.ruoyi.group.mapper.CustGroupMemberMapper;
import com.ruoyi.group.service.ICustGroupService;
import com.ruoyi.ibs.grid.domain.entity.RegionCustUser;
import com.ruoyi.ibs.handler.DynamicTableNameHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * 客群Service实现
 *
 * @author ruoyi
 */
@Service
@Slf4j
public class CustGroupServiceImpl implements ICustGroupService {

    @Resource
    private CustGroupMapper custGroupMapper;

    @Resource
    private CustGroupMemberMapper custGroupMemberMapper;

    @Resource(name = "excelImportExecutor")
    private ExecutorService executorService;

    @Resource
    private GridCmpmService gridCmpmService;

    @Resource
    private RegionGridListService regionGridListService;

    @Resource
    private DrawGridCustUserUnbindMapper drawGridCustUserUnbindMapper;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public List<CustGroupVO> listCustGroup(CustGroupQueryDTO dto) {
        return custGroupMapper.selectCustGroupList(dto);
    }

    @Override
    public CustGroupVO getCustGroup(Long id) {
        CustGroupVO custGroup = custGroupMapper.selectCustGroupById(id);
        if (custGroup == null) {
            throw new ServiceException("客群不存在");
        }
        return custGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createCustGroupByTemplate(CustGroup custGroup, MultipartFile file) {
        // 检查客群名称是否存在
        if (checkGroupNameExist(custGroup.getGroupName())) {
            throw new ServiceException("客群名称已存在");
        }
        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        custGroup.setUserName(user.getUserName());
        custGroup.setNickName(user.getNickName());
        // 设置默认值
        custGroup.setGroupMode("0"); // 静态
        custGroup.setCreateMode("1"); // 模板导入
        if (StringUtils.isEmpty(custGroup.getGroupStatus())) {
            custGroup.setGroupStatus("0");
        }
        // 设置创建状态为创建中
        custGroup.setCreateStatus("0");
        // 插入客群
        custGroupMapper.insert(custGroup);
        // 获取当前用户部门编码（异步线程中无法获取）
        String headId = SecurityUtils.getHeadId();
        // 异步导入客户
        executorService.submit(() -> doImportCustGroupByTemplate(custGroup, file, headId));
        return String.valueOf(custGroup.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createCustGroupByGrid(GridImportDTO gridImportDTO) {
        CustGroup custGroup = gridImportDTO.getCustGroup();
        // 检查客群名称是否存在
        if (checkGroupNameExist(custGroup.getGroupName())) {
            throw new ServiceException("客群名称已存在");
        }
        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        custGroup.setUserName(user.getUserName());
        custGroup.setNickName(user.getNickName());
        // 默认状态为正常
        if (StringUtils.isEmpty(custGroup.getGroupStatus())) {
            custGroup.setGroupStatus("0");
        }
        // 设置创建模式和状态
        custGroup.setGroupMode(custGroup.getGroupMode());
        // 根据网格类型设置创建方式：0=模板导入, 2=绩效网格, 3=地理网格, 4=绘制网格
        String gridType = gridImportDTO.getGridType();
        if ("0".equals(gridType)) {
            custGroup.setCreateMode("2"); // 绩效网格
        } else if ("1".equals(gridType)) {
            custGroup.setCreateMode("3"); // 地理网格
        } else if ("2".equals(gridType)) {
            custGroup.setCreateMode("4"); // 绘制网格
        } else {
            throw new ServiceException("无效的网格类型");
        }

        // 保存网格导入条件（用于动态客群后续更新）
        custGroup.setGridType(gridImportDTO.getGridType());
        if ("0".equals(gridType)) {
            custGroup.setCmpmBizType(gridImportDTO.getCmpmBizType());
            if (gridImportDTO.getUserNames() != null && !gridImportDTO.getUserNames().isEmpty()) {
                custGroup.setGridUserNames(String.join(",", gridImportDTO.getUserNames()));
            }
        } else if ("1".equals(gridType)) {
            if (gridImportDTO.getRegionGridIds() != null && !gridImportDTO.getRegionGridIds().isEmpty()) {
                custGroup.setRegionGridIds(gridImportDTO.getRegionGridIds().stream()
                        .map(String::valueOf).collect(Collectors.joining(",")));
            }
        } else if ("2".equals(gridType)) {
            if (gridImportDTO.getDrawGridIds() != null && !gridImportDTO.getDrawGridIds().isEmpty()) {
                custGroup.setDrawGridIds(gridImportDTO.getDrawGridIds().stream()
                        .map(String::valueOf).collect(Collectors.joining(",")));
            }
        }

        // 设置创建状态为创建中
        custGroup.setCreateStatus("0");
        // 插入客群
        custGroupMapper.insert(custGroup);
        // 重新设置回DTO（确保异步线程能获取到正确的ID和状态）
        gridImportDTO.setCustGroup(custGroup);
        // 获取当前用户部门编码（异步线程中无法获取）
        String headId = SecurityUtils.getHeadId();
        // 异步导入客户
        executorService.submit(() -> doImportCustGroupByGrid(gridImportDTO, headId));
        return String.valueOf(custGroup.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateCustGroupByGrid(GridImportDTO gridImportDTO) {
        CustGroup custGroup = gridImportDTO.getCustGroup();
        // 检查客群是否存在
        CustGroup existGroup = custGroupMapper.selectById(custGroup.getId());
        if (existGroup == null) {
            throw new ServiceException("客群不存在");
        }
        // 检查客群是否正在创建或更新
        if ("0".equals(existGroup.getCreateStatus())) {
            throw new ServiceException("客群正在处理中，请稍后再试");
        }
        // 更新客群基本信息
        if (!existGroup.getGroupName().equals(custGroup.getGroupName()) && checkGroupNameExist(custGroup.getGroupName())) {
            throw new ServiceException("客群名称已存在");
        }
        // 检查网格条件是否发生变化
        boolean gridConditionChanged = isGridConditionChanged(existGroup, gridImportDTO);

        // 重新查询数据库，获取最新状态
        CustGroup latestGroup = custGroupMapper.selectById(custGroup.getId());
        latestGroup.setGroupName(custGroup.getGroupName());
        latestGroup.setGroupMode(custGroup.getGroupMode());
        latestGroup.setRemark(custGroup.getRemark());
        latestGroup.setValidTime(custGroup.getValidTime());
        latestGroup.setShareEnabled(custGroup.getShareEnabled());
        latestGroup.setShareDeptIds(custGroup.getShareDeptIds());

        // 保存新的网格导入条件
        String gridType = gridImportDTO.getGridType();
        latestGroup.setGridType(gridType);
        if ("0".equals(gridType)) {
            latestGroup.setCmpmBizType(gridImportDTO.getCmpmBizType());
            if (gridImportDTO.getUserNames() != null && !gridImportDTO.getUserNames().isEmpty()) {
                latestGroup.setGridUserNames(String.join(",", gridImportDTO.getUserNames()));
            } else {
                latestGroup.setGridUserNames(null);
            }
        } else if ("1".equals(gridType)) {
            if (gridImportDTO.getRegionGridIds() != null && !gridImportDTO.getRegionGridIds().isEmpty()) {
                latestGroup.setRegionGridIds(gridImportDTO.getRegionGridIds().stream()
                        .map(String::valueOf).collect(Collectors.joining(",")));
            } else {
                latestGroup.setRegionGridIds(null);
            }
        } else if ("2".equals(gridType)) {
            if (gridImportDTO.getDrawGridIds() != null && !gridImportDTO.getDrawGridIds().isEmpty()) {
                latestGroup.setDrawGridIds(gridImportDTO.getDrawGridIds().stream()
                        .map(String::valueOf).collect(Collectors.joining(",")));
            } else {
                latestGroup.setDrawGridIds(null);
            }
        }

        // 更新数据库
        latestGroup.setUpdateBy(SecurityUtils.getUsername());
        latestGroup.setUpdateTime(new Date());
        custGroupMapper.updateById(latestGroup);

        // 如果网格条件没有变化，直接返回成功
        if (!gridConditionChanged) {
            log.info("客群网格条件未变化，跳过客户重新导入，客群ID：{}", custGroup.getId());
            return "客群更新成功（客户列表无需变更）";
        }

        // 网格条件发生变化，需要重新导入客户
        log.info("客群网格条件已变化，开始重新导入客户，客群ID：{}", custGroup.getId());
        // 设置更新状态为"更新中"
        latestGroup.setCreateStatus("0");
        custGroupMapper.updateById(latestGroup);
        // 重新设置回DTO（确保异步线程能获取到正确的ID和状态）
        gridImportDTO.setCustGroup(latestGroup);
        // 获取当前用户部门编码（异步线程中无法获取）
        String headId = SecurityUtils.getHeadId();
        // 异步导入客户
        executorService.submit(() -> doImportCustGroupByGrid(gridImportDTO, headId));
        return "客群更新中";
    }

    /**
     * 检查网格条件是否发生变化
     */
    private boolean isGridConditionChanged(CustGroup existGroup, GridImportDTO gridImportDTO) {
        // 首先检查网格类型是否变化
        String newGridType = gridImportDTO.getGridType();
        String oldGridType = existGroup.getGridType();

        // 如果旧记录没有网格类型信息，说明需要导入
        if (oldGridType == null) {
            return true;
        }

        // 网格类型变化
        if (!newGridType.equals(oldGridType)) {
            log.info("网格类型变化：旧={}, 新={}", oldGridType, newGridType);
            return true;
        }

        // 根据网格类型检查具体条件
        if ("0".equals(newGridType)) {
            // 绩效网格：比较业务类型和客户经理列表
            String oldBizType = existGroup.getCmpmBizType();
            String newBizType = gridImportDTO.getCmpmBizType();
            List<String> newUserNames = gridImportDTO.getUserNames();

            if (!Objects.equals(oldBizType, newBizType)) {
                log.info("绩效业务类型变化：旧={}, 新={}", oldBizType, newBizType);
                return true;
            }

            // 比较客户经理列表
            String oldUserNames = existGroup.getGridUserNames();
            String newUserNamesStr = newUserNames == null || newUserNames.isEmpty()
                    ? null : String.join(",", newUserNames);
            if (!Objects.equals(oldUserNames, newUserNamesStr)) {
                log.info("客户经理列表变化：旧={}, 新={}", oldUserNames, newUserNamesStr);
                return true;
            }
        } else if ("1".equals(newGridType)) {
            // 地理网格：比较网格ID列表
            String oldRegionIds = existGroup.getRegionGridIds();
            List<Long> newRegionIds = gridImportDTO.getRegionGridIds();
            String newRegionIdsStr = newRegionIds == null || newRegionIds.isEmpty()
                    ? null : newRegionIds.stream().map(String::valueOf).sorted().collect(Collectors.joining(","));

            // 归一化比较（排序后比较）
            String oldRegionIdsSorted = oldRegionIds == null ? null :
                    Arrays.stream(oldRegionIds.split(",")).sorted().collect(Collectors.joining(","));

            if (!Objects.equals(oldRegionIdsSorted, newRegionIdsStr)) {
                log.info("地理网格ID列表变化：旧={}, 新={}", oldRegionIdsSorted, newRegionIdsStr);
                return true;
            }
        } else if ("2".equals(newGridType)) {
            // 绘制网格：比较网格ID列表
            String oldDrawIds = existGroup.getDrawGridIds();
            List<Long> newDrawIds = gridImportDTO.getDrawGridIds();
            String newDrawIdsStr = newDrawIds == null || newDrawIds.isEmpty()
                    ? null : newDrawIds.stream().map(String::valueOf).sorted().collect(Collectors.joining(","));

            // 归一化比较（排序后比较）
            String oldDrawIdsSorted = oldDrawIds == null ? null :
                    Arrays.stream(oldDrawIds.split(",")).sorted().collect(Collectors.joining(","));

            if (!Objects.equals(oldDrawIdsSorted, newDrawIdsStr)) {
                log.info("绘制网格ID列表变化：旧={}, 新={}", oldDrawIdsSorted, newDrawIdsStr);
                return true;
            }
        }

        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateCustGroupByTemplate(CustGroup custGroup, MultipartFile file) {
        // 检查客群是否存在
        CustGroup existGroup = custGroupMapper.selectById(custGroup.getId());
        if (existGroup == null) {
            throw new ServiceException("客群不存在");
        }
        // 检查客群是否正在创建或更新
        if ("0".equals(existGroup.getCreateStatus())) {
            throw new ServiceException("客群正在处理中，请稍后再试");
        }
        // 更新客群基本信息
        if (!existGroup.getGroupName().equals(custGroup.getGroupName()) && checkGroupNameExist(custGroup.getGroupName())) {
            throw new ServiceException("客群名称已存在");
        }
        // 重新查询数据库，获取最新状态
        CustGroup latestGroup = custGroupMapper.selectById(custGroup.getId());
        latestGroup.setGroupName(custGroup.getGroupName());
        latestGroup.setGroupMode(custGroup.getGroupMode());
        latestGroup.setRemark(custGroup.getRemark());
        latestGroup.setValidTime(custGroup.getValidTime());
        latestGroup.setShareEnabled(custGroup.getShareEnabled());
        latestGroup.setShareDeptIds(custGroup.getShareDeptIds());
        // 设置更新状态为"更新中"
        latestGroup.setCreateStatus("0");
        // 更新数据库
        latestGroup.setUpdateBy(SecurityUtils.getUsername());
        latestGroup.setUpdateTime(new Date());
        custGroupMapper.updateById(latestGroup);
        // 获取当前用户部门编码（异步线程中无法获取）
        String headId = SecurityUtils.getHeadId();
        // 异步导入客户（使用最新状态的对象）
        executorService.submit(() -> doImportCustGroupByTemplate(latestGroup, file, headId));
        return "客群更新中";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deleteCustGroup(List<Long> idList) {
        if (idList == null || idList.isEmpty()) {
            throw new ServiceException("请选择要删除的客群");
        }
        for (Long id : idList) {
            // 删除客群客户关联
            LambdaQueryWrapper<CustGroupMember> memberWrapper = new LambdaQueryWrapper<>();
            memberWrapper.eq(CustGroupMember::getGroupId, id);
            custGroupMemberMapper.delete(memberWrapper);
            // 删除客群
            custGroupMapper.deleteById(id);
        }
        return "客群删除成功";
    }

    @Override
    public boolean checkGroupNameExist(String groupName) {
        LambdaQueryWrapper<CustGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CustGroup::getGroupName, groupName);
        return custGroupMapper.selectCount(wrapper) > 0;
    }

    @Override
    public String getCreateStatus(Long id) {
        CustGroup custGroup = custGroupMapper.selectById(id);
        if (custGroup == null) {
            throw new ServiceException("客群不存在");
        }
        return custGroup.getCreateStatus();
    }

    @Override
    public void updateDynamicCustGroups() {
        log.info("开始更新动态客群...");

        // 查询所有动态客群
        LambdaQueryWrapper<CustGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CustGroup::getGroupMode, "1");  // 1=动态
        wrapper.eq(CustGroup::getGroupStatus, "0"); // 0=正常
        wrapper.eq(CustGroup::getCreateStatus, "1"); // 1=创建成功
        List<CustGroup> dynamicGroups = custGroupMapper.selectList(wrapper);

        if (dynamicGroups.isEmpty()) {
            log.info("没有需要更新的动态客群");
            return;
        }

        log.info("找到 {} 个动态客群需要更新", dynamicGroups.size());
        Date now = new Date();

        for (CustGroup custGroup : dynamicGroups) {
            // 检查有效期，过期的客群跳过更新
            if (custGroup.getValidTime() != null && custGroup.getValidTime().before(now)) {
                log.info("动态客群已过期，跳过更新，客群ID：{}，客群名称：{}，有效期：{}",
                        custGroup.getId(), custGroup.getGroupName(), custGroup.getValidTime());
                continue;
            }

            try {
                updateDynamicCustGroup(custGroup);
                log.info("动态客群更新成功，客群ID：{}，客群名称：{}", custGroup.getId(), custGroup.getGroupName());
            } catch (Exception e) {
                log.error("动态客群更新失败，客群ID：{}，客群名称：{}", custGroup.getId(), custGroup.getGroupName(), e);
            }
        }

        log.info("动态客群更新完成，总计：{}，成功：{}，失败：{}",
                dynamicGroups.size(),
                dynamicGroups.stream().filter(g -> {
                    // 假设更新成功的状态设置
                    LambdaQueryWrapper<CustGroup> w = new LambdaQueryWrapper<>();
                    w.eq(CustGroup::getId, g.getId());
                    // 这里简单统计，实际可以通过更精确的方式
                    return true;
                }).count(),
                0);
    }

    @Override
    public void checkAndDisableExpiredGroups() {
        log.info("开始检查并禁用过期客群...");

        Date now = new Date();

        // 查询所有正常状态且有过期时间的客群
        LambdaQueryWrapper<CustGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CustGroup::getGroupStatus, "0"); // 0=正常
        wrapper.isNotNull(CustGroup::getValidTime);
        wrapper.le(CustGroup::getValidTime, now); // validTime <= now
        List<CustGroup> expiredGroups = custGroupMapper.selectList(wrapper);

        if (expiredGroups.isEmpty()) {
            log.info("没有需要禁用的过期客群");
            return;
        }

        log.info("找到 {} 个过期客群需要禁用", expiredGroups.size());

        for (CustGroup custGroup : expiredGroups) {
            try {
                custGroup.setGroupStatus("1"); // 1=已禁用
                custGroupMapper.updateById(custGroup);
                log.info("客群已禁用，客群ID：{}，客群名称：{}，有效期：{}",
                        custGroup.getId(), custGroup.getGroupName(), custGroup.getValidTime());
            } catch (Exception e) {
                log.error("禁用过期客群失败，客群ID：{}，客群名称：{}", custGroup.getId(), custGroup.getGroupName(), e);
            }
        }

        log.info("过期客群禁用完成，总计：{}", expiredGroups.size());
    }

    /**
     * 更新单个动态客群（增量更新方式）
     */
    private void updateDynamicCustGroup(CustGroup custGroup) {
        // 从客群部门获取 headId（定时任务中无登录用户上下文）
        // headId 是 deptId 的前三位
        String headId = "";
        if (custGroup.getDeptId() != null) {
            String deptIdStr = String.valueOf(custGroup.getDeptId());
            headId = deptIdStr.substring(0, 3);
        }

        // 查询现有客户（排除手动移除的客户，只查询正常状态的客户）
        LambdaQueryWrapper<CustGroupMember> existWrapper = new LambdaQueryWrapper<>();
        existWrapper.eq(CustGroupMember::getGroupId, custGroup.getId())
                .eq(CustGroupMember::getDelFlag, 0)
                .eq(CustGroupMember::getManualRemove, 0)
                .select(CustGroupMember::getCustId, CustGroupMember::getCustType);
        List<CustGroupMember> existMembers = custGroupMemberMapper.selectList(existWrapper);
        Set<String> existKeySet = existMembers.stream()
                .map(m -> m.getCustId() + "_" + m.getCustType())
                .collect(Collectors.toSet());

        // 构造 GridImportDTO 复用现有导入方法
        GridImportDTO gridImportDTO = new GridImportDTO();
        gridImportDTO.setCustGroup(custGroup);
        gridImportDTO.setGridType(custGroup.getGridType());
        gridImportDTO.setCmpmBizType(custGroup.getCmpmBizType());

        // 根据网格类型设置参数并查询
        List<CustGroupMember> newMemberList = new ArrayList<>();
        String gridType = custGroup.getGridType();
        if ("0".equals(gridType)) {
            // 绩效网格
            if (StringUtils.isNotEmpty(custGroup.getGridUserNames())) {
                gridImportDTO.setUserNames(Arrays.asList(custGroup.getGridUserNames().split(",")));
            }
            newMemberList.addAll(importFromCmpmGrid(custGroup, gridImportDTO, headId));
        } else if ("1".equals(gridType)) {
            // 地理网格
            if (StringUtils.isNotEmpty(custGroup.getRegionGridIds())) {
                gridImportDTO.setRegionGridIds(Arrays.stream(custGroup.getRegionGridIds().split(","))
                        .map(Long::valueOf).collect(Collectors.toList()));
            }
            newMemberList.addAll(importFromRegionGrid(custGroup, gridImportDTO, headId));
        } else if ("2".equals(gridType)) {
            // 绘制网格
            if (StringUtils.isNotEmpty(custGroup.getDrawGridIds())) {
                gridImportDTO.setDrawGridIds(Arrays.stream(custGroup.getDrawGridIds().split(","))
                        .map(Long::valueOf).collect(Collectors.toList()));
            }
            newMemberList.addAll(importFromDrawGrid(custGroup, gridImportDTO, headId));
        }

        // 计算差异
        Set<String> newKeySet = newMemberList.stream()
                .map(m -> m.getCustId() + "_" + m.getCustType())
                .collect(Collectors.toSet());

        // 需要删除的客户：存在于旧列表但不存在于新列表
        List<String> toDeleteKeys = new ArrayList<>(existKeySet);
        toDeleteKeys.removeAll(newKeySet);
        // 需要新增的客户：存在于新列表但不存在于旧列表
        List<CustGroupMember> toAddMembers = newMemberList.stream()
                .filter(m -> !existKeySet.contains(m.getCustId() + "_" + m.getCustType()))
                .collect(Collectors.toList());

        // 删除不再存在的客户
        if (!toDeleteKeys.isEmpty()) {
            for (String key : toDeleteKeys) {
                String[] parts = key.split("_");
                LambdaQueryWrapper<CustGroupMember> deleteWrapper = new LambdaQueryWrapper<>();
                deleteWrapper.eq(CustGroupMember::getGroupId, custGroup.getId())
                        .eq(CustGroupMember::getCustId, parts[0])
                        .eq(CustGroupMember::getCustType, parts[1]);
                custGroupMemberMapper.delete(deleteWrapper);
            }
        }

        // 插入新增客户
        int addCount = 0;
        for (CustGroupMember member : toAddMembers) {
            try {
                custGroupMemberMapper.insert(member);
                addCount++;
            } catch (org.springframework.dao.DuplicateKeyException e) {
                log.debug("客户已存在，跳过：groupId={}, custId={}", member.getGroupId(), member.getCustId());
            }
        }

        log.info("客群客户更新完成，客群ID：{}，原数量：{}，新数量：{}，新增：{}，删除：{}",
                custGroup.getId(), existMembers.size(), newMemberList.size(), addCount, toDeleteKeys.size());
    }

    /**
     * 异步导入客户
     */
    private void doImportCustGroupByTemplate(CustGroup custGroup, MultipartFile file, String headId) {
        try {
            // 解析Excel
            List<CustGroupMemberTemplate> templateList = EasyExcel.read(file.getInputStream())
                    .head(CustGroupMemberTemplate.class)
                    .sheet()
                    .doReadSync();
            if (templateList.isEmpty()) {
                throw new ServiceException("导入列表为空");
            }
            // 校验和去重
            Set<String> uniqueCustIds = new HashSet<>();
            List<CustGroupMember> memberList = new ArrayList<>();
            for (CustGroupMemberTemplate template : templateList) {
                // 校验客户类型
                String custType = template.getCustType();
                if (StringUtils.isEmpty(custType)) {
                    throw new ServiceException("客户类型不能为空");
                }
                // 转换客户类型值
                String custTypeValue;
                switch (custType) {
                    case "个人":
                        custTypeValue = "0";
                        break;
                    case "企业":
                        custTypeValue = "2";
                        break;
                    case "商户":
                        custTypeValue = "1";
                        break;
                    default:
                        throw new ServiceException("客户类型填写错误，只能填写：个人、企业、商户");
                }
                // 客户号不能为空
                if (StringUtils.isEmpty(template.getCustId())) {
                    throw new ServiceException("客户号不能为空");
                }
                // 检查重复
                if (!uniqueCustIds.add(template.getCustId())) {
                    continue; // 跳过重复客户
                }
                // 创建客户成员
                CustGroupMember member = new CustGroupMember();
                member.setGroupId(custGroup.getId());
                member.setCustType(custTypeValue);
                member.setCustId(template.getCustId());
                member.setCustName(template.getCustName());
                member.setCustIdc(template.getCustIdc());
                member.setSocialCreditCode(template.getSocialCreditCode());
                member.setCreateTime(new Date());
                // 个人客户必须有身份证号
                if ("0".equals(custTypeValue) && StringUtils.isEmpty(member.getCustIdc())) {
                    throw new ServiceException("个人客户[" + template.getCustId() + "]身份证号不能为空");
                }
                // 企业/商户客户必须有统信码
                if (("1".equals(custTypeValue) || "2".equals(custTypeValue))
                        && StringUtils.isEmpty(member.getSocialCreditCode())) {
                    throw new ServiceException("企业/商户客户[" + template.getCustId() + "]统信码不能为空");
                }
                memberList.add(member);
            }

            // 使用编程式事务：先删除旧客户，再插入新客户
            transactionTemplate.executeWithoutResult(status -> {
                // 删除该客群的所有旧客户
                log.info("开始删除客群旧客户（模板导入），客群ID：{}", custGroup.getId());
                LambdaQueryWrapper<CustGroupMember> memberWrapper = new LambdaQueryWrapper<>();
                memberWrapper.eq(CustGroupMember::getGroupId, custGroup.getId());
                custGroupMemberMapper.delete(memberWrapper);
                log.info("客群旧客户删除完成（模板导入），客群ID：{}", custGroup.getId());

                // 批量插入新客户
                log.info("开始批量插入客户（模板导入），客群ID：{}，客户总数：{}", custGroup.getId(), memberList.size());
                int batchSize = 1000;
                int successCount = 0;
                int skippedCount = 0;
                int restoredCount = 0;
                for (int i = 0; i < memberList.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, memberList.size());
                    List<CustGroupMember> batchList = memberList.subList(i, endIndex);
                    log.info("处理批次 [{}/{}]，本批大小：{}", i / batchSize + 1, (memberList.size() + batchSize - 1) / batchSize, batchList.size());
                    for (CustGroupMember member : batchList) {
                        try {
                            custGroupMemberMapper.insert(member);
                            successCount++;
                        } catch (DuplicateKeyException e) {
                            // 客户已存在，检查是否是被手动移除的
                            LambdaQueryWrapper<CustGroupMember> queryWrapper = new LambdaQueryWrapper<>();
                            queryWrapper.eq(CustGroupMember::getGroupId, member.getGroupId())
                                    .eq(CustGroupMember::getCustId, member.getCustId())
                                    .eq(CustGroupMember::getCustType, member.getCustType());
                            CustGroupMember existMember = custGroupMemberMapper.selectOne(queryWrapper);
                            if (existMember != null && existMember.getManualRemove() != null && existMember.getManualRemove() == 1) {
                                // 是被手动移除的客户，清除标记并恢复
                                existMember.setManualRemove(0);
                                existMember.setDelFlag(0);
                                existMember.setCustName(member.getCustName());
                                custGroupMemberMapper.updateById(existMember);
                                restoredCount++;
                                log.debug("恢复手动移除的客户：groupId={}, custId={}", member.getGroupId(), member.getCustId());
                            } else {
                                // 正常存在的客户，跳过
                                skippedCount++;
                                log.debug("客户已存在，跳过：groupId={}, custId={}", member.getGroupId(), member.getCustId());
                            }
                        }
                    }
                }
                log.info("客群客户导入完成（模板），客群ID：{}，成功：{}，跳过重复：{}，恢复：{}",
                        custGroup.getId(), successCount, skippedCount, restoredCount);
                // 更新创建状态为成功
                custGroup.setCreateStatus("1");
                custGroup.setUpdateBy(custGroup.getCreateBy());
                custGroup.setUpdateTime(new Date());
                custGroupMapper.updateById(custGroup);
            });
        } catch (Exception e) {
            log.error("客群客户导入失败，客群ID：{}，异常：{}", custGroup.getId(), e.getMessage(), e);

            // 注意：由于删除和插入在同一事务中，插入失败会自动回滚删除操作，无需手动清理

            // 更新创建状态为失败
            custGroup.setCreateStatus("2");
            custGroup.setUpdateBy(custGroup.getCreateBy());
            custGroup.setUpdateTime(new Date());
            custGroupMapper.updateById(custGroup);
            throw new ServiceException("客群客户导入失败: " + e.getMessage());
        }
    }

    /**
     * 异步导入客户（网格方式）
     */
    private void doImportCustGroupByGrid(GridImportDTO gridImportDTO, String headId) {
        CustGroup custGroup = gridImportDTO.getCustGroup();
        try {
            List<CustGroupMember> memberList = new ArrayList<>();
            String gridType = gridImportDTO.getGridType();
            // 根据网格类型查询客户
            if ("0".equals(gridType)) {
                // 绩效网格
                memberList.addAll(importFromCmpmGrid(custGroup, gridImportDTO, headId));
            } else if ("1".equals(gridType)) {
                // 地理网格
                memberList.addAll(importFromRegionGrid(custGroup, gridImportDTO, headId));
            } else if ("2".equals(gridType)) {
                // 绘制网格
                memberList.addAll(importFromDrawGrid(custGroup, gridImportDTO, headId));
            }
            if (memberList.isEmpty()) {
                throw new ServiceException("未查询到任何客户");
            }

            // 使用编程式事务：先删除旧客户，再插入新客户
            transactionTemplate.executeWithoutResult(status -> {
                // 删除该客群的所有旧客户
                log.info("开始删除客群旧客户，客群ID：{}", custGroup.getId());
                LambdaQueryWrapper<CustGroupMember> memberWrapper = new LambdaQueryWrapper<>();
                memberWrapper.eq(CustGroupMember::getGroupId, custGroup.getId());
                custGroupMemberMapper.delete(memberWrapper);
                log.info("客群旧客户删除完成，客群ID：{}", custGroup.getId());

                // 批量插入新客户
                log.info("开始批量插入客户，客群ID：{}，客户总数：{}", custGroup.getId(), memberList.size());

                // 分批批量插入（每批1000条）
                int batchSize = 1000;
                int totalInserted = 0;
                int totalRestored = 0;
                int totalSkipped = 0;

                for (int i = 0; i < memberList.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, memberList.size());
                    List<CustGroupMember> batchList = memberList.subList(i, endIndex);
                    log.info("处理批次 [{}/{}]，本批大小：{}", i / batchSize + 1,
                        (memberList.size() + batchSize - 1) / batchSize, batchList.size());

                    // SQL层面的批量插入
                    custGroupMemberMapper.batchInsertMembers(batchList);

                    // 查询本批中被手动移除的客户，需要恢复
                    List<CustGroupMember> toRestore = findManualRemovedToRestore(custGroup.getId(), batchList);
                    if (!toRestore.isEmpty()) {
                        // 恢复被手动移除的客户
                        for (CustGroupMember m : toRestore) {
                            batchList.stream()
                                .filter(b -> b.getCustId().equals(m.getCustId()) && b.getCustType().equals(m.getCustType()))
                                .findFirst()
                                .ifPresent(origin -> m.setCustName(origin.getCustName()));
                            m.setManualRemove(0);
                            custGroupMemberMapper.updateById(m);
                        }
                        log.info("本批恢复被手动移除的客户：{} 条", toRestore.size());
                        totalRestored += toRestore.size();
                    }

                    totalInserted += batchList.size() - toRestore.size();
                    totalSkipped += toRestore.size();
                }

                log.info("客群客户导入完成（网格），客群ID：{}，插入：{}，恢复：{}，跳过：{}",
                        custGroup.getId(), totalInserted, totalRestored, totalSkipped);

                // 更新创建状态为成功
                custGroup.setCreateStatus("1");
                custGroup.setUpdateBy(custGroup.getCreateBy());
                custGroup.setUpdateTime(new Date());
                log.info("准备更新客群状态为成功，客群ID：{}", custGroup.getId());
                custGroupMapper.updateById(custGroup);
                log.info("客群状态更新成功完成，客群ID：{}", custGroup.getId());
            });
        } catch (Exception e) {
            // 先记录原始异常（必须第一时间记录，避免后续异常覆盖）
            log.error("==========客群客户导入异常========== 客群ID：{}，异常类型：{}，异常消息：{}",
                custGroup.getId(), e.getClass().getName(), e.getMessage(), e);

            // 注意：由于删除和插入在同一事务中，插入失败会自动回滚删除操作，无需手动清理

            // 更新创建状态为失败
            try {
                custGroup.setCreateStatus("2");
                custGroup.setUpdateBy(custGroup.getCreateBy());
                custGroup.setUpdateTime(new Date());
                log.info("准备更新客群状态为失败，客群ID：{}", custGroup.getId());
                custGroupMapper.updateById(custGroup);
                log.info("客群状态更新为失败完成，客群ID：{}", custGroup.getId());
            } catch (Exception updateException) {
                log.error("==========更新客群状态为失败也异常了========== 客群ID：{}，异常类型：{}，异常消息：{}",
                    custGroup.getId(), updateException.getClass().getName(), updateException.getMessage(), updateException);
            }
            throw new ServiceException("客群客户导入失败: " + e.getMessage());
        }
    }

    /**
     * 查找需要恢复的被手动移除的客户
     *
     * @param groupId 客群ID
     * @param batchList 本批导入的客户列表
     * @return 需要恢复的客户列表
     */
    private List<CustGroupMember> findManualRemovedToRestore(Long groupId, List<CustGroupMember> batchList) {
        // 构建本批客户的 (custId, custType) 集合
        Set<String> batchKeys = batchList.stream()
            .map(m -> m.getCustId() + "|" + m.getCustType())
            .collect(Collectors.toSet());

        // 查询该客群所有被手动移除的客户
        LambdaQueryWrapper<CustGroupMember> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CustGroupMember::getGroupId, groupId)
                .eq(CustGroupMember::getManualRemove, 1)
                .eq(CustGroupMember::getDelFlag, 0);
        List<CustGroupMember> manualRemovedList = custGroupMemberMapper.selectList(queryWrapper);

        // 筛选出本批中需要恢复的
        return manualRemovedList.stream()
            .filter(m -> batchKeys.contains(m.getCustId() + "|" + m.getCustType()))
            .collect(Collectors.toList());
    }

    /**
     * 从绩效网格导入客户
     */
    private List<CustGroupMember> importFromCmpmGrid(CustGroup custGroup, GridImportDTO gridImportDTO, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        // 确定要查询的网格类型
        List<String> gridTypes = new ArrayList<>();
        String cmpmBizType = gridImportDTO.getCmpmBizType();
        if ("retail".equals(cmpmBizType)) {
            gridTypes.add("retail");
        } else if ("corporate".equals(cmpmBizType)) {
            gridTypes.add("corporate");
            gridTypes.add("corporate_account");
        } else {
            throw new ServiceException("请选择绩效网格业务类型（零售/对公/对公账户）");
        }
        // 查询客户
        for (String userName : gridImportDTO.getUserNames()) {
            for (String gridType : gridTypes) {
                List<GridCmpmVO> cmpmList = gridCmpmService.selectManageListForImport(gridType, userName, headId);
                for (GridCmpmVO cmpm : cmpmList) {
                    CustGroupMember member = new CustGroupMember();
                    member.setGroupId(custGroup.getId());
                    member.setCustId(cmpm.getCustId());
                    member.setCustName(cmpm.getCustName());
                    member.setCustType(cmpm.getCustType());
                    member.setCustIdc(cmpm.getCustIdc());
                    member.setSocialCreditCode(cmpm.getUsci());
                    member.setCreateTime(new Date());
                    memberList.add(member);
                }
            }
        }
        return memberList;
    }

    /**
     * 从地理网格导入客户
     */
    private List<CustGroupMember> importFromRegionGrid(CustGroup custGroup, GridImportDTO gridImportDTO, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        if (gridImportDTO.getRegionGridIds() == null || gridImportDTO.getRegionGridIds().isEmpty()) {
            throw new ServiceException("请选择地理网格");
        }
        // 直接根据网格ID列表批量查询所有客户（SQL中直接拼接headId，绕过MyBatis-Plus拦截器）
        List<RegionCustUser> custUsers = regionGridListService.selectAllCustByGridIds(gridImportDTO.getRegionGridIds(), headId);
        for (RegionCustUser custUser : custUsers) {
            CustGroupMember member = new CustGroupMember();
            member.setGroupId(custGroup.getId());
            member.setCustId(custUser.getCustId());
            member.setCustName(custUser.getCustName());
            member.setCustType(custUser.getCustType());
            member.setCreateTime(new Date());
            memberList.add(member);
        }
        return memberList;
    }

    /**
     * 从绘制网格导入客户
     */
    private List<CustGroupMember> importFromDrawGrid(CustGroup custGroup, GridImportDTO gridImportDTO, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        if (gridImportDTO.getDrawGridIds() == null || gridImportDTO.getDrawGridIds().isEmpty()) {
            throw new ServiceException("请选择绘制网格");
        }
        // 使用 selectCustByDrawGridId 方法（直接在SQL中拼接headId，绕过拦截器）
        for (Long gridId : gridImportDTO.getDrawGridIds()) {
            List<RegionCustUser> custUsers = drawGridCustUserUnbindMapper.selectCustByDrawGridId(gridId, headId);
            if (custUsers != null && !custUsers.isEmpty()) {
                for (RegionCustUser custUser : custUsers) {
                    CustGroupMember member = new CustGroupMember();
                    member.setGroupId(custGroup.getId());
                    member.setCustId(custUser.getCustId());
                    member.setCustName(custUser.getCustName());
                    member.setCustType(custUser.getCustType());
                    member.setCreateTime(new Date());
                    memberList.add(member);
                }
            }
        }
        return memberList;
    }
}