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.ibs.cmpm.domain.vo.GridCmpmVO;
import com.ruoyi.ibs.cmpm.service.GridCmpmService;
import com.ruoyi.ibs.dashboard.service.NotificationService;
import com.ruoyi.ibs.draw.mapper.DrawGridShapeRelateMapper;
import com.ruoyi.ibs.grid.domain.entity.RegionCustUser;
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.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 lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
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 DrawGridShapeRelateMapper drawGridShapeRelateMapper;

    @Resource
    private NotificationService notificationService;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public List<CustGroupVO> listCustGroup(CustGroupQueryDTO dto) {
        dto.setHeadRole(isHeadCustGroupAdmin());
        return custGroupMapper.selectCustGroupList(
                dto,
                SecurityUtils.getUsername(),
                String.valueOf(SecurityUtils.getDeptId()),
                SecurityUtils.getHeadId()
        );
    }

    @Override
    public CustGroupVO getCustGroup(Long id) {
        CustGroupVO custGroup = custGroupMapper.selectCustGroupById(
                id,
                SecurityUtils.getUsername(),
                String.valueOf(SecurityUtils.getDeptId()),
                isHeadCustGroupAdmin(),
                SecurityUtils.getHeadId()
        );
        if (custGroup == null) {
            throw new ServiceException("客群不存在");
        }
        return custGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createCustGroupByTemplate(CustGroup custGroup, MultipartFile file) {
        assertHeadCustGroupAdmin();
        // 检查客群名称是否存在
        if (checkGroupNameExist(custGroup.getGroupName())) {
            throw new ServiceException("客群名称已存在");
        }
        // 获取当前用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();
        custGroup.setUserName(user.getUserName());
        custGroup.setNickName(user.getNickName());
        custGroup.setDeptId(SecurityUtils.getDeptId());
        // 设置默认值
        if (StringUtils.isEmpty(custGroup.getGroupMode())) {
            custGroup.setGroupMode("0"); // 静态
        }
        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 updateCustGroupByTemplate(CustGroup custGroup, MultipartFile file) {
        // 检查客群是否存在
        CustGroup existGroup = custGroupMapper.selectById(custGroup.getId());
        if (existGroup == null) {
            throw new ServiceException("客群不存在");
        }
        assertOperatePermission(existGroup);
        // 检查客群是否正在创建或更新
        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.setGroupTags(custGroup.getGroupTags());
        // 保存网格参数（从 custGroup 中获取）
        latestGroup.setGridType(custGroup.getGridType());
        latestGroup.setRegionGridIds(custGroup.getRegionGridIds());
        latestGroup.setDrawGridIds(custGroup.getDrawGridIds());
        latestGroup.setUpdateBy(SecurityUtils.getUsername());
        latestGroup.setUpdateTime(new Date());

        // 判断是否需要导入客户文件
        if (file != null && !file.isEmpty()) {
            // 有文件：设置状态为"更新中"，异步导入客户
            latestGroup.setCreateStatus("0");
            custGroupMapper.updateById(latestGroup);
            // 获取当前用户部门编码（异步线程中无法获取）
            String headId = SecurityUtils.getHeadId();
            // 异步导入客户（使用最新状态的对象）
            final CustGroup finalGroup = latestGroup;
            executorService.submit(() -> doImportCustGroupByTemplate(finalGroup, file, headId));
            return "客群更新中";
        } else {
            // 无文件：只更新客群信息，直接完成
            latestGroup.setCreateStatus("1");
            custGroupMapper.updateById(latestGroup);
            return "客群更新成功";
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deleteCustGroup(List<Long> idList) {
        if (idList == null || idList.isEmpty()) {
            throw new ServiceException("请选择要删除的客群");
        }
        for (Long id : idList) {
            CustGroup custGroup = custGroupMapper.selectById(id);
            if (custGroup == null) {
                throw new ServiceException("客群不存在");
            }
            assertOperatePermission(custGroup);
            // 删除客群客户关联
            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);
        wrapper.ne(CustGroup::getCreateStatus, "2");
        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 checkCustGroupViewPermission(Long id) {
        Long count = custGroupMapper.countVisibleCustGroup(
                id,
                SecurityUtils.getUsername(),
                String.valueOf(SecurityUtils.getDeptId()),
                isHeadCustGroupAdmin(),
                SecurityUtils.getHeadId()
        );
        if (count == null || count <= 0) {
            throw new ServiceException("客群不存在或无查看权限");
        }
    }

    public boolean isHeadCustGroupAdmin() {
        return SecurityUtils.hasRole("headAdmin")
                || SecurityUtils.hasRole("headPublic")
                || SecurityUtils.hasRole("headPrivate")
                || SecurityUtils.hasRole("headOps");
    }

    public void assertHeadCustGroupAdmin() {
        if (!isHeadCustGroupAdmin()) {
            throw new ServiceException("当前用户无权限操作该功能");
        }
    }

    private void assertOperatePermission(CustGroup custGroup) {
        assertHeadCustGroupAdmin();
        Long count = custGroupMapper.countHeadOperableCustGroup(custGroup.getId(), SecurityUtils.getHeadId());
        if (count == null || count <= 0) {
            throw new ServiceException("无权限操作该客群");
        }
    }

    @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();
        int successCount = 0;
        int failureCount = 0;

        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);
                successCount++;
                log.info("动态客群更新成功，客群ID：{}，客群名称：{}", custGroup.getId(), custGroup.getGroupName());
            } catch (Exception e) {
                failureCount++;
                log.error("动态客群更新失败，客群ID：{}，客群名称：{}", custGroup.getId(), custGroup.getGroupName(), e);
            }
        }

        log.info("动态客群更新完成，总计：{}，成功：{}，失败：{}",
                dynamicGroups.size(),
                successCount,
                failureCount);
    }

    @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) {
        transactionTemplate.executeWithoutResult(status -> {
            try {
                // 从客群部门获取 headId（定时任务中无登录用户上下文）
                String headId = "";
                if (custGroup.getDeptId() != null) {
                    String deptIdStr = String.valueOf(custGroup.getDeptId());
                    headId = deptIdStr.length() >= 3 ? deptIdStr.substring(0, 3) : deptIdStr;
                }

                // 查询现有客户成员（排除手动移除的客户）
                LambdaQueryWrapper<CustGroupMember> existWrapper = new LambdaQueryWrapper<>();
                existWrapper.eq(CustGroupMember::getGroupId, custGroup.getId())
                        .eq(CustGroupMember::getDelFlag, 0)
                        .eq(CustGroupMember::getManualRemove, 0);
                List<CustGroupMember> existMembers = custGroupMemberMapper.selectList(existWrapper);

                if (existMembers.isEmpty()) {
                    log.info("客群中没有客户，跳过更新，客群ID：{}", custGroup.getId());
                    return;
                }

                Map<String, CustGroupMember> baseMemberMap = new LinkedHashMap<>();
                Map<String, List<CustGroupMember>> existMemberMap = new LinkedHashMap<>();
                for (CustGroupMember member : existMembers) {
                    String key = buildCustKey(member.getCustId(), member.getCustType());
                    baseMemberMap.putIfAbsent(key, member);
                    existMemberMap.computeIfAbsent(key, k -> new ArrayList<>()).add(member);
                }

                Map<String, List<CustGroupMember>> gridRelMap = queryGridRelationshipsMap(custGroup, new ArrayList<>(baseMemberMap.values()), headId);

                int updateCount = 0;
                int insertCount = 0;
                int deleteCount = 0;

                for (Map.Entry<String, CustGroupMember> entry : baseMemberMap.entrySet()) {
                    String key = entry.getKey();
                    CustGroupMember baseMember = entry.getValue();
                    List<CustGroupMember> currentList = existMemberMap.getOrDefault(key, Collections.emptyList());
                    List<CustGroupMember> desiredList = buildDesiredMembers(baseMember, gridRelMap.get(key));

                    int commonSize = Math.min(currentList.size(), desiredList.size());
                    for (int i = 0; i < commonSize; i++) {
                        CustGroupMember current = currentList.get(i);
                        CustGroupMember desired = desiredList.get(i);
                        current.setUserName(desired.getUserName());
                        current.setNickName(desired.getNickName());
                        current.setOutletId(desired.getOutletId());
                        current.setOutletName(desired.getOutletName());
                        current.setBranchId(desired.getBranchId());
                        current.setBranchName(desired.getBranchName());
                        current.setUpdateTime(new Date());
                        custGroupMemberMapper.updateById(current);
                        updateCount++;
                    }

                    for (int i = commonSize; i < currentList.size(); i++) {
                        custGroupMemberMapper.deleteById(currentList.get(i).getId());
                        deleteCount++;
                    }

                    for (int i = commonSize; i < desiredList.size(); i++) {
                        CustGroupMember newMember = desiredList.get(i);
                        newMember.setGroupId(custGroup.getId());
                        newMember.setCreateTime(new Date());
                        custGroupMemberMapper.insert(newMember);
                        insertCount++;
                    }
                }

                log.info("客群管户关系更新完成，客群ID：{}，客户数：{}，更新：{}，新增：{}，删除：{}",
                        custGroup.getId(), baseMemberMap.size(), updateCount, insertCount, deleteCount);
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
    }

    /**
     * 从对应网格查询客户的最新管户关系，返回 Map（key = custId_custType）
     */
    private Map<String, List<CustGroupMember>> queryGridRelationshipsMap(CustGroup custGroup, List<CustGroupMember> members, String headId) {
        Map<String, List<CustGroupMember>> result = new LinkedHashMap<>();
        String gridType = custGroup.getGridType();

        if (StringUtils.isEmpty(gridType)) {
            log.warn("动态客群未配置网格类型，跳过管户关系更新，客群ID：{}", custGroup.getId());
            return result;
        }

        if ("0".equals(gridType)) {
            fillCmpmRelationships(result, members, headId);
        } else if ("1".equals(gridType)) {
            fillRegionRelationships(result, parseGridIds(custGroup.getRegionGridIds()), members, headId);
        } else if ("2".equals(gridType)) {
            fillDrawRelationships(result, parseGridIds(custGroup.getDrawGridIds()), members, headId);
        } else {
            log.warn("动态客群网格类型暂不支持，客群ID：{}，gridType：{}", custGroup.getId(), gridType);
        }
        return result;
    }

    private void fillCmpmRelationships(Map<String, List<CustGroupMember>> result, List<CustGroupMember> members, String headId) {
        List<Map<String, String>> retailCustList = new ArrayList<>();
        List<Map<String, String>> corporateCustList = new ArrayList<>();

        for (CustGroupMember member : members) {
            Map<String, String> custInfo = new HashMap<>();
            custInfo.put("custId", member.getCustId());
            custInfo.put("custType", member.getCustType());
            if ("0".equals(member.getCustType()) || "1".equals(member.getCustType())) {
                retailCustList.add(custInfo);
            } else if ("2".equals(member.getCustType())) {
                corporateCustList.add(custInfo);
            }
        }

        if (!retailCustList.isEmpty()) {
            List<GridCmpmVO> relationships = gridCmpmService.getRelationshipsByCustList("retail", headId, retailCustList);
            for (GridCmpmVO cmpm : relationships) {
                CustGroupMember member = new CustGroupMember();
                member.setUserName(cmpm.getUserName());
                member.setNickName(cmpm.getNickName());
                member.setOutletId(cmpm.getOutletId());
                member.setOutletName(cmpm.getOutletName());
                member.setBranchId(cmpm.getBranchId());
                member.setBranchName(cmpm.getBranchName());
                addRelationship(result, buildCustKey(cmpm.getCustId(), cmpm.getCustType()), member);
            }
        }

        if (!corporateCustList.isEmpty()) {
            List<GridCmpmVO> relationships = gridCmpmService.getRelationshipsByCustList("corporate", headId, corporateCustList);
            for (GridCmpmVO cmpm : relationships) {
                CustGroupMember member = new CustGroupMember();
                member.setUserName(cmpm.getUserName());
                member.setNickName(cmpm.getNickName());
                member.setOutletId(cmpm.getOutletId());
                member.setOutletName(cmpm.getOutletName());
                member.setBranchId(cmpm.getBranchId());
                member.setBranchName(cmpm.getBranchName());
                addRelationship(result, buildCustKey(cmpm.getCustId(), cmpm.getCustType()), member);
            }
        }
    }

    private void fillRegionRelationships(Map<String, List<CustGroupMember>> result, List<Long> regionGridIds,
                                         List<CustGroupMember> members, String headId) {
        if (regionGridIds == null || regionGridIds.isEmpty()) {
            return;
        }

        Set<String> targetCustKeys = members.stream()
                .map(member -> buildCustKey(member.getCustId(), member.getCustType()))
                .collect(Collectors.toSet());

        List<RegionCustUser> custUsers = regionGridListService.selectAllCustByGridIds(regionGridIds, headId);
        for (RegionCustUser custUser : custUsers) {
            String key = buildCustKey(custUser.getCustId(), custUser.getCustType());
            if (!targetCustKeys.contains(key)) {
                continue;
            }
            addRegionCustUserRelationships(result, key, custUser);
        }
    }

    private void fillDrawRelationships(Map<String, List<CustGroupMember>> result, List<Long> drawGridIds,
                                       List<CustGroupMember> members, String headId) {
        if (drawGridIds == null || drawGridIds.isEmpty()) {
            return;
        }

        Set<String> targetCustKeys = members.stream()
                .map(member -> buildCustKey(member.getCustId(), member.getCustType()))
                .collect(Collectors.toSet());

        for (Long gridId : drawGridIds) {
            List<RegionCustUser> custUsers = drawGridShapeRelateMapper.selectCustByDrawGridId(gridId, headId);
            if (custUsers == null || custUsers.isEmpty()) {
                continue;
            }
            for (RegionCustUser custUser : custUsers) {
                String key = buildCustKey(custUser.getCustId(), custUser.getCustType());
                if (!targetCustKeys.contains(key)) {
                    continue;
                }
                addRegionCustUserRelationships(result, key, custUser);
            }
        }
    }

    private void addRegionCustUserRelationships(Map<String, List<CustGroupMember>> result, String key, RegionCustUser custUser) {
        String[] userNames = custUser.getUserNames() != null ? custUser.getUserNames().split(",") : new String[0];
        String[] nickNames = custUser.getNickNames() != null ? custUser.getNickNames().split(",") : new String[0];
        String[] outletIds = custUser.getOutletIds() != null ? custUser.getOutletIds().split(",") : new String[0];
        String[] outletNames = custUser.getOutletNames() != null ? custUser.getOutletNames().split(",") : new String[0];
        String[] branchIds = custUser.getBranchIds() != null ? custUser.getBranchIds().split(",") : new String[0];
        String[] branchNames = custUser.getBranchNames() != null ? custUser.getBranchNames().split(",") : new String[0];

        int count = Math.max(userNames.length, 1);
        for (int i = 0; i < count; i++) {
            CustGroupMember member = new CustGroupMember();
            member.setUserName(i < userNames.length ? userNames[i] : null);
            member.setNickName(i < nickNames.length ? nickNames[i] : null);
            member.setOutletId(parseLongValue(i < outletIds.length ? outletIds[i] : null));
            member.setOutletName(i < outletNames.length ? outletNames[i] : null);
            member.setBranchId(parseLongValue(i < branchIds.length ? branchIds[i] : null));
            member.setBranchName(i < branchNames.length ? branchNames[i] : null);
            addRelationship(result, key, member);
        }
    }

    private void addRelationship(Map<String, List<CustGroupMember>> result, String key, CustGroupMember relationship) {
        List<CustGroupMember> relationshipList = result.computeIfAbsent(key, k -> new ArrayList<>());
        boolean exists = relationshipList.stream().anyMatch(item ->
                Objects.equals(StringUtils.trimToNull(item.getUserName()), StringUtils.trimToNull(relationship.getUserName()))
                        && Objects.equals(StringUtils.trimToNull(item.getNickName()), StringUtils.trimToNull(relationship.getNickName()))
                        && Objects.equals(item.getOutletId(), relationship.getOutletId())
                        && Objects.equals(StringUtils.trimToNull(item.getOutletName()), StringUtils.trimToNull(relationship.getOutletName()))
                        && Objects.equals(item.getBranchId(), relationship.getBranchId())
                        && Objects.equals(StringUtils.trimToNull(item.getBranchName()), StringUtils.trimToNull(relationship.getBranchName())));
        if (!exists) {
            relationshipList.add(relationship);
        }
    }

    private List<CustGroupMember> buildDesiredMembers(CustGroupMember baseMember, List<CustGroupMember> relationships) {
        List<CustGroupMember> result = new ArrayList<>();
        if (relationships == null || relationships.isEmpty()) {
            CustGroupMember member = copyBaseMember(baseMember);
            clearRelationshipFields(member);
            result.add(member);
            return result;
        }

        for (CustGroupMember relationship : relationships) {
            CustGroupMember member = copyBaseMember(baseMember);
            member.setUserName(relationship.getUserName());
            member.setNickName(relationship.getNickName());
            member.setOutletId(relationship.getOutletId());
            member.setOutletName(relationship.getOutletName());
            member.setBranchId(relationship.getBranchId());
            member.setBranchName(relationship.getBranchName());
            result.add(member);
        }
        return result;
    }

    private CustGroupMember copyBaseMember(CustGroupMember source) {
        CustGroupMember target = new CustGroupMember();
        target.setGroupId(source.getGroupId());
        target.setCustType(source.getCustType());
        target.setCustId(source.getCustId());
        target.setCustName(source.getCustName());
        target.setCustIdc(source.getCustIdc());
        target.setSocialCreditCode(source.getSocialCreditCode());
        target.setCreateBy(source.getCreateBy());
        return target;
    }

    private void clearRelationshipFields(CustGroupMember member) {
        member.setUserName(null);
        member.setNickName(null);
        member.setOutletId(null);
        member.setOutletName(null);
        member.setBranchId(null);
        member.setBranchName(null);
    }

    private String buildCustKey(String custId, String custType) {
        return custId + "_" + custType;
    }

    private Long parseLongValue(String value) {
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        return Long.valueOf(value.trim());
    }

    /**
     * 异步导入客户（模板导入 + 管户关系匹配）
     */
    private void doImportCustGroupByTemplate(CustGroup custGroup, MultipartFile file, String headId) {
        try {
            // 1. 解析Excel获取客户信息
            List<CustGroupMemberTemplate> templateList = EasyExcel.read(file.getInputStream())
                    .head(CustGroupMemberTemplate.class)
                    .sheet()
                    .doReadSync();
            if (templateList.isEmpty()) {
                throw new ServiceException("导入列表为空");
            }

            // 2. 校验和去重，构建客户信息Map (custId + custType -> CustGroupMember)
            Map<String, CustGroupMember> custInfoMap = new LinkedHashMap<>();
            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("客户类型填写错误，只能填写：个人、企业、商户");
                }
                // 校验客户类型与客群类型是否匹配
                String groupType = custGroup.getGroupType();
                if ("0".equals(groupType)) {
                    // 零售类客群：只允许个人(0)和商户(1)
                    if (!"0".equals(custTypeValue) && !"1".equals(custTypeValue)) {
                        throw new ServiceException("零售类客群只能导入个人和商户客户，客户[" + template.getCustId() + "]类型为" + custType + "，不符合要求");
                    }
                } else if ("1".equals(groupType)) {
                    // 公司类客群：只允许企业(2)
                    if (!"2".equals(custTypeValue)) {
                        throw new ServiceException("公司类客群只能导入企业客户，客户[" + template.getCustId() + "]类型为" + custType + "，不符合要求");
                    }
                }
                // 客户号不能为空
                if (StringUtils.isEmpty(template.getCustId())) {
                    throw new ServiceException("客户号不能为空");
                }
                // 构建唯一键
                String key = template.getCustId() + "_" + custTypeValue;
                if (custInfoMap.containsKey(key)) {
                    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() + "]统信码不能为空");
                }
                custInfoMap.put(key, member);
            }

            final int[] successCount = {0};
            final int[] skippedCount = {0};

            transactionTemplate.executeWithoutResult(status -> {
                try {
                    // 3. 从网格中查询管户关系
                    List<CustGroupMember> relationshipList = queryCustRelationships(custGroup, headId);

                    // 4. 构建管户关系Map (custId + custType -> List<CustGroupMember>)
                    Map<String, List<CustGroupMember>> relationshipMap = new HashMap<>();
                    for (CustGroupMember rel : relationshipList) {
                        String key = rel.getCustId() + "_" + rel.getCustType();
                        relationshipMap.computeIfAbsent(key, k -> new ArrayList<>()).add(rel);
                    }

                    // 5. 合并客户信息和管户关系，生成最终成员列表
                    List<CustGroupMember> memberList = new ArrayList<>();
                    for (Map.Entry<String, CustGroupMember> entry : custInfoMap.entrySet()) {
                        String key = entry.getKey();
                        CustGroupMember custInfo = entry.getValue();
                        List<CustGroupMember> relationships = relationshipMap.get(key);

                        if (relationships != null && !relationships.isEmpty()) {
                            for (CustGroupMember rel : relationships) {
                                CustGroupMember member = new CustGroupMember();
                                member.setGroupId(custGroup.getId());
                                member.setCustType(custInfo.getCustType());
                                member.setCustId(custInfo.getCustId());
                                member.setCustName(custInfo.getCustName());
                                member.setCustIdc(custInfo.getCustIdc());
                                member.setSocialCreditCode(custInfo.getSocialCreditCode());
                                member.setCreateTime(new Date());
                                member.setUserName(rel.getUserName());
                                member.setNickName(rel.getNickName());
                                member.setOutletId(rel.getOutletId());
                                member.setOutletName(rel.getOutletName());
                                member.setBranchId(rel.getBranchId());
                                member.setBranchName(rel.getBranchName());
                                memberList.add(member);
                            }
                        } else {
                            memberList.add(custInfo);
                        }
                    }

                    log.info("开始批量插入客户（模板导入），客群ID：{}，客户总数：{}", custGroup.getId(), memberList.size());
                    for (CustGroupMember member : memberList) {
                        try {
                            custGroupMemberMapper.insert(member);
                            successCount[0]++;
                        } catch (DuplicateKeyException e) {
                            skippedCount[0]++;
                            log.debug("客户已存在，跳过：groupId={}, custId={}", member.getGroupId(), member.getCustId());
                        }
                    }

                    log.info("客群客户导入完成（模板），客群ID：{}，成功：{}，跳过重复：{}",
                            custGroup.getId(), successCount[0], skippedCount[0]);
                    custGroup.setCreateStatus("1");
                    custGroup.setUpdateBy(custGroup.getCreateBy());
                    custGroup.setUpdateTime(new Date());
                    custGroupMapper.updateById(custGroup);
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            });
            // 发送成功通知
            String successMsg = String.format("客群【%s】导入完成，成功导入 %d 条客户数据", custGroup.getGroupName(), successCount[0]);
            notificationService.sendNotification(custGroup.getCreateBy(), successMsg);
        } catch (Exception e) {
            log.error("客群客户导入失败，客群ID：{}，异常：{}", custGroup.getId(), e.getMessage(), e);

            transactionTemplate.executeWithoutResult(status -> {
                custGroup.setCreateStatus("2");
                custGroup.setUpdateBy(custGroup.getCreateBy());
                custGroup.setUpdateTime(new Date());
                custGroupMapper.updateById(custGroup);
            });
            // 发送失败通知
            String failMsg = String.format("客群【%s】导入失败：%s", custGroup.getGroupName(), e.getMessage());
            notificationService.sendNotification(custGroup.getCreateBy(), failMsg);
        }
    }

    /**
     * 解析网格ID字符串为List
     */
    private List<Long> parseGridIds(String gridIdsStr) {
        if (StringUtils.isEmpty(gridIdsStr)) {
            return null;
        }
        return Arrays.stream(gridIdsStr.split(","))
                .filter(StringUtils::isNotEmpty)
                .map(Long::valueOf)
                .collect(Collectors.toList());
    }

    /**
     * 从网格中查询管户关系
     */
    private List<CustGroupMember> queryCustRelationships(CustGroup custGroup, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        String gridType = custGroup.getGridType();
        List<Long> regionGridIds = parseGridIds(custGroup.getRegionGridIds());
        List<Long> drawGridIds = parseGridIds(custGroup.getDrawGridIds());

        if (StringUtils.isEmpty(gridType)) {
            return memberList;
        }

        if ("0".equals(gridType)) {
            memberList.addAll(queryRelationshipsFromCmpmGrid(custGroup, headId));
        } else if ("1".equals(gridType)) {
            memberList.addAll(queryRelationshipsFromRegionGrid(custGroup, regionGridIds, headId));
        } else if ("2".equals(gridType)) {
            memberList.addAll(queryRelationshipsFromDrawGrid(custGroup, drawGridIds, headId));
        }

        return memberList;
    }

    /**
     * 从绩效网格查询管户关系（全量匹配）
     */
    private List<CustGroupMember> queryRelationshipsFromCmpmGrid(CustGroup custGroup, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        List<String> gridTypes = new ArrayList<>();
        String groupType = custGroup.getGroupType();

        if ("0".equals(groupType)) {
            gridTypes.add("retail");
        } else if ("1".equals(groupType)) {
            gridTypes.add("corporate");
        } else {
            return memberList;
        }

        for (String gridType : gridTypes) {
            List<GridCmpmVO> cmpmList = gridCmpmService.selectAllForImport(gridType, headId);
            for (GridCmpmVO cmpm : cmpmList) {
                CustGroupMember member = new CustGroupMember();
                member.setGroupId(custGroup.getId());
                member.setCustId(cmpm.getCustId());
                member.setCustType(cmpm.getCustType());
                member.setUserName(cmpm.getUserName());
                member.setNickName(cmpm.getNickName());
                member.setOutletId(cmpm.getOutletId());
                member.setOutletName(cmpm.getOutletName());
                member.setBranchId(cmpm.getBranchId());
                member.setBranchName(cmpm.getBranchName());
                memberList.add(member);
            }
        }
        return memberList;
    }

    /**
     * 从地理网格查询管户关系
     */
    private List<CustGroupMember> queryRelationshipsFromRegionGrid(CustGroup custGroup, List<Long> regionGridIds, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        if (regionGridIds == null || regionGridIds.isEmpty()) {
            return memberList;
        }

        List<RegionCustUser> custUsers = regionGridListService.selectAllCustByGridIds(regionGridIds, headId);
        for (RegionCustUser custUser : custUsers) {
            String[] userNames = custUser.getUserNames() != null ? custUser.getUserNames().split(",") : new String[0];
            String[] nickNames = custUser.getNickNames() != null ? custUser.getNickNames().split(",") : new String[0];
            String[] outletIds = custUser.getOutletIds() != null ? custUser.getOutletIds().split(",") : new String[0];
            String[] outletNames = custUser.getOutletNames() != null ? custUser.getOutletNames().split(",") : new String[0];
            String[] branchIds = custUser.getBranchIds() != null ? custUser.getBranchIds().split(",") : new String[0];
            String[] branchNames = custUser.getBranchNames() != null ? custUser.getBranchNames().split(",") : new String[0];

            int count = Math.max(userNames.length, 1);
            for (int i = 0; i < count; i++) {
                CustGroupMember member = new CustGroupMember();
                member.setGroupId(custGroup.getId());
                member.setCustId(custUser.getCustId());
                member.setCustType(custUser.getCustType());
                member.setUserName(i < userNames.length ? userNames[i] : null);
                member.setNickName(i < nickNames.length ? nickNames[i] : null);
                member.setOutletId(i < outletIds.length && StringUtils.isNotEmpty(outletIds[i]) ? Long.valueOf(outletIds[i]) : null);
                member.setOutletName(i < outletNames.length ? outletNames[i] : null);
                member.setBranchId(i < branchIds.length && StringUtils.isNotEmpty(branchIds[i]) ? Long.valueOf(branchIds[i]) : null);
                member.setBranchName(i < branchNames.length ? branchNames[i] : null);
                memberList.add(member);
            }
        }
        return memberList;
    }

    /**
     * 从绘制网格查询管户关系
     */
    private List<CustGroupMember> queryRelationshipsFromDrawGrid(CustGroup custGroup, List<Long> drawGridIds, String headId) {
        List<CustGroupMember> memberList = new ArrayList<>();
        if (drawGridIds == null || drawGridIds.isEmpty()) {
            return memberList;
        }

        for (Long gridId : drawGridIds) {
            List<RegionCustUser> custUsers = drawGridShapeRelateMapper.selectCustByDrawGridId(gridId, headId);
            if (custUsers != null && !custUsers.isEmpty()) {
                for (RegionCustUser custUser : custUsers) {
                    String[] userNames = custUser.getUserNames() != null ? custUser.getUserNames().split(",") : new String[0];
                    String[] nickNames = custUser.getNickNames() != null ? custUser.getNickNames().split(",") : new String[0];
                    String[] outletIds = custUser.getOutletIds() != null ? custUser.getOutletIds().split(",") : new String[0];
                    String[] outletNames = custUser.getOutletNames() != null ? custUser.getOutletNames().split(",") : new String[0];
                    String[] branchIds = custUser.getBranchIds() != null ? custUser.getBranchIds().split(",") : new String[0];
                    String[] branchNames = custUser.getBranchNames() != null ? custUser.getBranchNames().split(",") : new String[0];

                    int count = Math.max(userNames.length, 1);
                    for (int i = 0; i < count; i++) {
                        CustGroupMember member = new CustGroupMember();
                        member.setGroupId(custGroup.getId());
                        member.setCustId(custUser.getCustId());
                        member.setCustType(custUser.getCustType());
                        member.setUserName(i < userNames.length ? userNames[i] : null);
                        member.setNickName(i < nickNames.length ? nickNames[i] : null);
                        member.setOutletId(i < outletIds.length && StringUtils.isNotEmpty(outletIds[i]) ? Long.valueOf(outletIds[i]) : null);
                        member.setOutletName(i < outletNames.length ? outletNames[i] : null);
                        member.setBranchId(i < branchIds.length && StringUtils.isNotEmpty(branchIds[i]) ? Long.valueOf(branchIds[i]) : null);
                        member.setBranchName(i < branchNames.length ? branchNames[i] : null);
                        memberList.add(member);
                    }
                }
            }
        }
        return memberList;
    }

    @Override
    public List<String> getAllGroupTags() {
        // 查询所有已有标签（逗号分隔的字符串）
        List<String> tagStrings = custGroupMapper.selectAllGroupTags();
        if (tagStrings == null || tagStrings.isEmpty()) {
            return new ArrayList<>();
        }

        // 将逗号分隔的标签拆分并去重
        Set<String> tagSet = new LinkedHashSet<>();
        for (String tagString : tagStrings) {
            if (StringUtils.isNotEmpty(tagString)) {
                String[] tags = tagString.split(",");
                for (String tag : tags) {
                    String trimmedTag = tag.trim();
                    if (StringUtils.isNotEmpty(trimmedTag)) {
                        tagSet.add(trimmedTag);
                    }
                }
            }
        }

        return new ArrayList<>(tagSet);
    }
}
