package com.ruoyi.ibs.grid.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysDept;
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.common.utils.bean.BeanUtils;
import com.ruoyi.ibs.enumertion.CustIdTypeEnum;
import com.ruoyi.ibs.enumertion.CustTypeEnum;
import com.ruoyi.ibs.grid.domain.dto.virtual.VirtualCustDTO;
import com.ruoyi.ibs.grid.domain.dto.virtual.VirtualCustUserDTO;
import com.ruoyi.ibs.grid.domain.dto.virtual.VirtualGridDTO;
import com.ruoyi.ibs.grid.domain.entity.*;
import com.ruoyi.ibs.grid.domain.excel.VirtualCustUserImportDTO;
import com.ruoyi.ibs.grid.mapper.*;
import com.ruoyi.ibs.grid.service.GridInfoRedisService;
import com.ruoyi.ibs.grid.service.VirtualGridAsyncService;
import com.ruoyi.ibs.grid.service.VirtualGridCustService;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class VirtualGridAsyncServiceImpl implements VirtualGridAsyncService {

    @Resource
    private VirtualCustUserMapper virtualCustUserMapper;

    @Resource
    private VirtualCustMapper virtualCustMapper;

    @Resource
    private VirtualGridMapper virtualGridMapper;

    @Resource
    private SysDeptMapper sysDeptMapper;

    @Resource
    private SysUserMapper sysUserMapper;


    @Resource
    private VirtualUserMapper virtualUserMapper;

    @Resource
    private VirtualGridRuleMapper virtualGridRuleMapper;

    @Resource
    private GridInfoRedisService gridInfoRedisService;

    @Resource
    private VirtualGridCustService virtualGridCustService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertCustAsync(Long gridId, VirtualGridDTO virtualGridDTO, MultipartFile file) {
        VirtualGrid updateGrid = new VirtualGrid();
        updateGrid.setGridId(gridId);
        try{
            //excel文件解析+校验
            InputStream inputStream = new ByteArrayInputStream(file.getBytes());
            List<VirtualCustDTO> custDTOList = EasyExcel.read(inputStream).head(VirtualCustDTO.class).sheet().doReadSync();
            custDTOList.forEach(virtualCustImportDTO -> {
                if (StringUtils.isEmpty(virtualCustImportDTO.getCustIdType())) {
                    virtualCustImportDTO.setCustIdType(CustIdTypeEnum.getByCode(virtualCustImportDTO.getCustId().substring(0, 3)).getName());
                }
                if (StringUtils.isEmpty(virtualCustImportDTO.getCustIdn())) {
                    virtualCustImportDTO.setCustIdn(virtualCustImportDTO.getCustId().substring(3));
                }
            });
            virtualGridDTO.setCustDTOList(custDTOList);
            if (virtualGridDTO.getCreateMode().equals("1")) {
                custDTOList.forEach(custDTO -> {
                    if (Objects.isNull(custDTO.getCustType())
                            || Objects.isNull(custDTO.getCustIdn())
                            || Objects.isNull(custDTO.getCustId())) {
                        throw new ServiceException("创建失败，存在客户信息缺失！");
                    }
                    if (Objects.isNull(CustTypeEnum.getByName(custDTO.getCustType()))) {
                        throw new ServiceException("客户类型错误！");
                    }
                });

                List<String> custIds = custDTOList.stream().map(VirtualCustDTO::getCustId).distinct().collect(Collectors.toList());
                if (custIds.size() != custDTOList.size()) {
                    throw new ServiceException("客户列表存在重复客户！");
                }
                if (virtualGridDTO.getHasBusiness() && custDTOList.stream().noneMatch(virtualCustDTO -> virtualCustDTO.getCustType().equals(CustTypeEnum.ENTERPRISE.getName()))) {
                    throw new ServiceException("未上传客户类型为企业的客户！");
                }
                if (virtualGridDTO.getHasRetail() && custDTOList.stream().noneMatch(virtualCustDTO -> virtualCustDTO.getCustType().equals(CustTypeEnum.PERSONAL.getName()))) {
                    throw new ServiceException("未上传客户类型为个人的客户！");
                }
                if (virtualGridDTO.getHasRetailBusiness() && custDTOList.stream().noneMatch(virtualCustDTO -> virtualCustDTO.getCustType().equals(CustTypeEnum.MERCHANT.getName()))) {
                    throw new ServiceException("未上传客户类型为商户的客户！");
                }
            }
            // 插入客户
            custDTOList.forEach(virtualGridCustDTO -> {
                VirtualCust virtualCust = new VirtualCust();
                BeanUtils.copyProperties(virtualGridCustDTO, virtualCust);
                CustTypeEnum custType = CustTypeEnum.getByName(virtualGridCustDTO.getCustType());
                virtualCust.setCustType(custType);
                CustIdTypeEnum custIdType = CustIdTypeEnum.getByName(virtualGridCustDTO.getCustIdType());
                virtualCust.setCustIdType(custIdType);
                virtualCust.setGridId(gridId);
                virtualCustMapper.insert(virtualCust);
            });
            // 指定客户经理：插入客户经理，插入客户-客户经理关系
            if (virtualGridDTO.getGridAssignType().equals("1")) {
                // 插入客户经理
                virtualGridDTO.getGridUserRelateDTOList().forEach(gridUserRelateDTO -> {
                    if (gridUserRelateDTO.getRelateType().equals("2")) {
                        throw new ServiceException("虚拟网格创建失败 不可以绑定机构");
                    }
                    VirtualUser virtualUser = new VirtualUser();
                    BeanUtils.copyProperties(gridUserRelateDTO, virtualUser);
                    virtualUser.setGridId(gridId);
                    virtualUserMapper.insert(virtualUser);

                    // 插入客户-客户经理关系
                    virtualGridDTO.getCustDTOList().forEach(virtualGridCustDTO -> {
                        VirtualCustUser virtualCustUser = new VirtualCustUser();
                        BeanUtils.copyProperties(gridUserRelateDTO, virtualCustUser);
                        virtualCustUser.setGridId(gridId);
                        virtualCustUser.setCustId(virtualGridCustDTO.getCustId());
                        virtualCustUserMapper.insert(virtualCustUser);
                    });
                });
                // 插入网格分配规则
            } else if (virtualGridDTO.getGridAssignType().equals("2")) {
                virtualGridDTO.getVirtualGridRuleDTOList().forEach(virtualGridRuleDTO -> {
                    VirtualGridRule virtualGridRule = new VirtualGridRule();
                    BeanUtils.copyProperties(virtualGridRuleDTO, virtualGridRule);
                    virtualGridRule.setRelateType(CustTypeEnum.getByName(virtualGridRuleDTO.getRelateType()));
                    virtualGridRule.setGridId(gridId);
                    virtualGridRuleMapper.insert(virtualGridRule);
                    if (virtualGridRuleDTO.getRuleKey().equals(3)) {
                        List<VirtualCustDTO> virtualCustDTOS = custDTOList.stream()
                                .filter(virtualCustDTO -> virtualCustDTO.getCustType().equals(virtualGridRuleDTO.getRelateType()))
                                .collect(Collectors.toList());
                        for (VirtualCustDTO virtualCustDTO : virtualCustDTOS) {
                            VirtualCustUser virtualCustUser = new VirtualCustUser();
                            virtualCustUser.setGridId(gridId);
                            virtualCustUser.setCustId(virtualCustDTO.getCustId());
                            virtualCustUserMapper.insert(virtualCustUser);
                        }
                    }
                });
            }
            gridInfoRedisService.cleanGridInfo("3");
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String format = simpleDateFormat.format(new Date().getTime());
            String headId = SecurityUtils.getHeadId();
            virtualGridCustService.updateToCustInfo(headId, custDTOList, SecurityUtils.getUsername(), format);
            // 更新为成功状态
            updateGrid.setCreateStatus(1);
            virtualGridMapper.updateById(updateGrid);
        }catch (Exception e){
            log.error("网格客户导入失败，正在清理相关数据，网格ID：{}", gridId, e);
            cleanupFailedGrid(gridId);
            // 更新为失败状态
            updateGrid.setCreateStatus(2);
            virtualGridMapper.updateById(updateGrid);
            throw new ServiceException("网格客户导入失败" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertCustRelateAsync(Long gridId, VirtualGridDTO virtualGridRelateAddDTO, MultipartFile file) {
        VirtualGrid updateGrid = new VirtualGrid();
        updateGrid.setGridId(gridId);

        try {
            //excel文件解析+校验
            InputStream inputStream = new ByteArrayInputStream(file.getBytes());
            List<VirtualCustUserImportDTO> virtualCustImportDTOS = EasyExcel.read(inputStream).head(VirtualCustUserImportDTO.class).sheet().doReadSync();
            Set<String> filter = new HashSet<>();
            List<VirtualCustUserImportDTO> collect = virtualCustImportDTOS.stream().filter(virtualCustUserImportDTO -> filter.add(virtualCustUserImportDTO.getCustId() + '-' + virtualCustUserImportDTO.getUserName()))
                    .collect(Collectors.toList());
            if (!collect.isEmpty()) {
                collect.forEach(virtualCustImportDTO -> {
                    virtualCustImportDTO.checkValid();
                    if (!StringUtils.isNotEmpty(virtualCustImportDTO.getCustIdType())) {
                        virtualCustImportDTO.setCustIdType(CustIdTypeEnum.getByCode(virtualCustImportDTO.getCustId().substring(0, 3)).getName());
                    }
                    if (!StringUtils.isNotEmpty(virtualCustImportDTO.getCustIdn())) {
                        virtualCustImportDTO.setCustIdn(virtualCustImportDTO.getCustId().substring(3));
                    }
                });
            }
            List<String> custCollect = collect.stream()
                    .map(virtualCustUserDTO -> virtualCustUserDTO.getCustId()).distinct().collect(Collectors.toList());

            List<VirtualCustDTO> virtualCustDTOList = new ArrayList<>();
            custCollect.forEach(custId -> {
                VirtualCustUserDTO custDTO = virtualGridRelateAddDTO.getVirtualCustUserDTOList().stream().filter(virtualCustUserDTO -> virtualCustUserDTO.getCustId().equals(custId))
                        .findFirst().orElse(null);
                if (Objects.nonNull(custDTO)) {
                    VirtualCust virtualCust = new VirtualCust();
                    BeanUtils.copyProperties(custDTO, virtualCust);
                    CustTypeEnum custType = CustTypeEnum.getByName(custDTO.getCustType());
                    virtualCust.setCustType(custType);
                    CustIdTypeEnum custIdType = CustIdTypeEnum.getByName(custDTO.getCustIdType());
                    virtualCust.setCustIdType(custIdType);
                    virtualCust.setLockFlag(Boolean.TRUE);
                    virtualCust.setGridId(gridId);
                    virtualCustMapper.insert(virtualCust);

                    VirtualCustDTO virtualCustDTO = new VirtualCustDTO();
                    BeanUtils.copyProperties(custDTO, virtualCustDTO);
                    virtualCustDTOList.add(virtualCustDTO);
                }
            });

            List<String> userCollect = virtualGridRelateAddDTO.getVirtualCustUserDTOList().stream()
                    .map(virtualCustUserDTO -> virtualCustUserDTO.getUserName()).distinct().collect(Collectors.toList());
            userCollect.forEach(userName -> {
                SysUser sysUser = sysUserMapper.selectUserByUserName(userName);
                if (Objects.isNull(sysUser)) {
                    throw new ServiceException("存在未知客户经理：" + userName);
                }
                SysDept sysDept1 = sysDeptMapper.selectDeptById(sysUser.getDeptId());
                VirtualUser virtualUser = new VirtualUser();
                virtualUser.setGridId(gridId);
                virtualUser.setUserName(sysUser.getUserName());
                virtualUser.setNickName(sysUser.getNickName());
                virtualUser.setRelateType("1");
                virtualUser.setRelateDeptId(sysDept1.getDeptId());
                virtualUser.setRelateDeptName(sysDept1.getDeptName());
                virtualUser.setRelateDeptType(sysDept1.getDeptType());
                virtualUserMapper.insert(virtualUser);

                List<VirtualCustUserDTO> custUserCollect = virtualGridRelateAddDTO.getVirtualCustUserDTOList().stream()
                        .filter(virtualCustUserDTO -> virtualCustUserDTO.getUserName().equals(userName))
                        .collect(Collectors.toList());
                custUserCollect.forEach(dto -> {
                    VirtualCustUser virtualCustUser = new VirtualCustUser();
                    virtualCustUser.setGridId(gridId);
                    virtualCustUser.setCustId(dto.getCustId());
                    virtualCustUser.setUserName(userName);
                    virtualCustUser.setNickName(sysUser.getNickName());
                    virtualCustUser.setRelateDeptId(sysDept1.getDeptId());
                    virtualCustUser.setRelateDeptName(sysDept1.getDeptName());
                    virtualCustUserMapper.insert(virtualCustUser);
                });
            });
            gridInfoRedisService.cleanGridInfo("3");
            if (!virtualCustDTOList.isEmpty()){
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String format = simpleDateFormat.format(new Date().getTime());
                String headId = SecurityUtils.getHeadId();
                virtualGridCustService.updateToCustInfo(headId, virtualCustDTOList, SecurityUtils.getUsername(), format);
            }

        }catch (Exception e) {
            log.error("网格管户导入失败，正在清理相关数据，网格ID：{}", gridId, e);
            cleanupFailedGrid(gridId);
            // 更新为失败状态
            updateGrid.setCreateStatus(2);
            virtualGridMapper.updateById(updateGrid);
            throw new ServiceException("网格客户导入失败" + e.getMessage());
        }
    }

    // 失败时清理数据
    private void cleanupFailedGrid(Long gridId) {
        try {
            log.info("开始清理失败网格数据，网格ID：{}", gridId);

            // 1. 清理客户-客户经理关系表数据
            LambdaQueryWrapper<VirtualCustUser> custUserWrapper = new LambdaQueryWrapper<>();
            custUserWrapper.eq(VirtualCustUser::getGridId, gridId);
            int custUserCount = virtualCustUserMapper.delete(custUserWrapper);
            log.info("清理客户-客户经理关系数据 {} 条，网格ID：{}", custUserCount, gridId);

            // 2. 清理客户表数据
            LambdaQueryWrapper<VirtualCust> custWrapper = new LambdaQueryWrapper<>();
            custWrapper.eq(VirtualCust::getGridId, gridId);
            int custCount = virtualCustMapper.delete(custWrapper);
            log.info("清理客户数据 {} 条，网格ID：{}", custCount, gridId);

            // 3. 清理虚拟用户表数据（客户经理）
            LambdaQueryWrapper<VirtualUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(VirtualUser::getGridId, gridId);
            int userCount = virtualUserMapper.delete(userWrapper);
            log.info("清理虚拟用户数据 {} 条，网格ID：{}", userCount, gridId);

            // 4. 清理网格分配规则表数据
            LambdaQueryWrapper<VirtualGridRule> ruleWrapper = new LambdaQueryWrapper<>();
            ruleWrapper.eq(VirtualGridRule::getGridId, gridId);
            int ruleCount = virtualGridRuleMapper.delete(ruleWrapper);
            log.info("清理网格分配规则数据 {} 条，网格ID：{}", ruleCount, gridId);

            // 5. 清理网格主表数据（如果需要）
            // virtualGridMapper.deleteById(gridId);
            // log.info("清理网格主表数据，网格ID：{}", gridId);

            log.info("网格数据清理完成，网格ID：{}", gridId);

        } catch (Exception e) {
            log.error("清理失败网格数据异常，网格ID：{}", gridId, e);
            // 不抛出异常，避免影响主流程的状态更新
        }
    }


}
