package com.ruoyi.ibs.cmpm.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.ibs.cmpm.domain.dto.CustLevelDTO;
import com.ruoyi.ibs.cmpm.domain.dto.CustManagerDTO;
import com.ruoyi.ibs.cmpm.domain.dto.GridCmpmListDTO;
import com.ruoyi.ibs.cmpm.domain.entity.GridCmpm;
import com.ruoyi.ibs.cmpm.domain.vo.DwbRetailCustLevelManagerDetailVO;
import com.ruoyi.ibs.cmpm.domain.vo.DwbRetailResultVO;
import com.ruoyi.ibs.cmpm.domain.vo.GridCmpmVO;
import com.ruoyi.ibs.cmpm.mapper.GridCmpmMapper;
import com.ruoyi.ibs.task.domain.entity.ImportExportTask;
import com.ruoyi.ibs.task.mapper.ImportExportTaskMapper;
import com.ruoyi.system.enums.OssFileEnum;
import com.ruoyi.system.service.OssFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author 吴凯程
 * @Date 2025/10/15
 **/
@Service
@Slf4j
public class GridCmpmService {


    @Resource
    private GridCmpmMapper gridCmpmMapper;

    @Resource
    private GridCmpmTransferService gridCmpmTransferService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private ImportExportTaskMapper importExportTaskMapper;

    @Resource
    private OssFileService ossFileService;

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

    private final String CUST_LEVEL_COUNT_KEY = "GRID_CMPM_CUST_LEVEL_COUNT_";

    public List<GridCmpmVO> selectManageList(GridCmpmListDTO gridCmpmRetailListDTO){
        String userRole = SecurityUtils.userRole();
         if("branch".equalsIgnoreCase(userRole)){
             gridCmpmRetailListDTO.setBranchId(SecurityUtils.getDeptId());
        }else if("outlet".equalsIgnoreCase(userRole)){
             gridCmpmRetailListDTO.setOutletId(SecurityUtils.getDeptId());
        }else if ("manager".equalsIgnoreCase(userRole)){
             gridCmpmRetailListDTO.setCurUserName(SecurityUtils.getUsername());
        }
         List<GridCmpm> gridCmpms = gridCmpmMapper.selectManageList(gridCmpmRetailListDTO);
         return gridCmpms.stream().map(gridCmpm -> {
             GridCmpmVO gridCmpmVO = new GridCmpmVO();
             BeanUtils.copyProperties(gridCmpm,gridCmpmVO);
             if (SecurityUtils.userRole().equals("branch") || SecurityUtils.userRole().equals("head") || SecurityUtils.isHead()){
                 gridCmpmVO.setTransferFlag( !gridCmpmTransferService.checkExistTransferCust(gridCmpm.getCustId(), gridCmpm.getUserName()) );
             }else{
                 // 无法移交条件： 1.客户存在移交审批中的记录 2.客户经理为当前用户
                 gridCmpmVO.setTransferFlag( (!gridCmpmTransferService.checkExistTransferCust(gridCmpm.getCustId(), gridCmpm.getUserName())) && gridCmpm.getUserName().equals(SecurityUtils.getUsername()) );
             }
             return gridCmpmVO;
         }).collect(Collectors.toList());
    }

    public List<GridCmpmVO> selectCommonList(GridCmpmListDTO gridCmpmListDTO){
        List<GridCmpm> gridCmpms = gridCmpmMapper.selectCommonList(gridCmpmListDTO);
        return gridCmpms.stream().map(gridCmpm -> {
            GridCmpmVO gridCmpmRetailVO = new GridCmpmVO();
            BeanUtils.copyProperties(gridCmpm,gridCmpmRetailVO);
            gridCmpmRetailVO.setTransferFlag(!gridCmpmTransferService.checkExistTransferCust(gridCmpm.getCustId(), null));
            return gridCmpmRetailVO;
        }).collect(Collectors.toList());
    }

    public String getCustLevelByCust(CustLevelDTO custLevelDTO){
        if (custLevelDTO.getCustType().equals("0") || custLevelDTO.getCustType().equals("1")){
            custLevelDTO.setGridType("retail");
            return gridCmpmMapper.getCustLevel(custLevelDTO);
        }else if (Objects.nonNull(custLevelDTO.getAccountNo())){
            custLevelDTO.setGridType("corporate_account");
        }else {
            custLevelDTO.setGridType("corporate");
        }
        // todo 公司部未上
        return null;
    }

    public List<String> getAllCustLevel(String gridType){
        String label = gridType +"_"+ SecurityUtils.getHeadId();
        ArrayList<SysDictData> custLevelList = redisCache.getCacheObject("sys_dict:grid_cmpm_cust_level");
        return custLevelList.stream().filter(sysDictData -> sysDictData.getDictLabel().equals(label)).map(sysDictData -> sysDictData.getDictValue()).sorted().collect(Collectors.toList());
    }

    public List<DwbRetailCustLevelManagerDetailVO> selectCustManagerList(CustManagerDTO custManagerDTO) {
        applyCustManagerScope(custManagerDTO);
        return gridCmpmMapper.getCustManagerList(custManagerDTO);
    }

    public String exportCustManagerAsync(CustManagerDTO custManagerDTO) {
        applyCustManagerScope(custManagerDTO);
        String headId = SecurityUtils.getHeadId();

        ImportExportTask task = new ImportExportTask();
        String taskId = IdUtils.randomUUID();
        task.setId(taskId);
        task.setStatus("0");
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        task.setFileName(sdf.format(now) + "管户报表导出");
        task.setUserName(SecurityUtils.getUsername());
        task.setCreateTime(now);
        importExportTaskMapper.insert(task);

        String userName = SecurityUtils.getUsername();
        executorService.submit(() -> doExportCustManager(taskId, custManagerDTO, userName, headId));
        return taskId;
    }

    public int custLevelCount(CustManagerDTO custManagerDTO) {
        applyCustManagerScope(custManagerDTO);
        return gridCmpmMapper.getCustLevelCount(custManagerDTO);
    }

    /**
     * 获取AUM统计数据(只查redis)
     */
    public DwbRetailResultVO selectCustManagerResult(){
        String userRole = SecurityUtils.userRole();
        String deptId = String.valueOf(SecurityUtils.getDeptId());
        String key ;
        if (userRole.equals("manager")){
            key = CUST_LEVEL_COUNT_KEY + userRole + "_" + SecurityUtils.getUsername();
        }else if (userRole.equals("outlet") || userRole.equals("branch")){
            key = CUST_LEVEL_COUNT_KEY + userRole + "_" + deptId;
        }else {
            key = CUST_LEVEL_COUNT_KEY + userRole;
        }
        try {
            if (redisCache.hasKey(key)){
                String json = redisCache.getCacheObject(key);
                if (json != null && !json.isEmpty()) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    return objectMapper.readValue(json, DwbRetailResultVO.class);
                }
            }
        } catch (Exception e) {
            throw new ServiceException("反序列化Redis缓存数据异常:" + key + e.getMessage());
        }
        return new DwbRetailResultVO();
    }

    /**
     * 获取管户报表星级列表
     */
    public List<String> getCustLevelListForManager() {
        return gridCmpmMapper.getCustLevelList();
    }

    /**
     * 每月定时设置统计数据
     */
    public void setCustManagerResultMonthly() {
        String[] roles = {"manager", "outlet", "branch", "head", "public", "private", "ops"};
        for (String role : roles) {
            setCustManagerResultByRole(role);
        }
    }

    /**
     * 根据角色获取AUM统计数据
     */
    private void setCustManagerResultByRole(String userRole) {
        CustManagerDTO custManagerDTO = new CustManagerDTO();

        if (userRole.equals("manager")){
            List<String> managerList = gridCmpmMapper.selectManagerList();
            if (managerList != null){
                for (String manager : managerList) {
                    String key = CUST_LEVEL_COUNT_KEY + userRole + "_" + manager;
                    custManagerDTO.setManagerId(manager);
                    processAndCacheResult(key, custManagerDTO);
                }
            }
        }else {
            //非客户经理角色——根据角色获取deptIds
            List<String> deptIds = gridCmpmMapper.selectDeptListByRole(userRole);
            if (deptIds.contains("head")){
                String key = CUST_LEVEL_COUNT_KEY + userRole;
                processAndCacheResult(key, custManagerDTO);
            }else {
                for (String deptId : deptIds) {
                    //redisKey用于存入redis供后续查询
                    String key = CUST_LEVEL_COUNT_KEY + userRole + "_" + deptId;
                    switch (userRole) {
                        case "outlet":
                            custManagerDTO.setOutletId(deptId);
                            break;
                        case "branch":
                            custManagerDTO.setBranchId(deptId);
                            break;
                    }
                    processAndCacheResult(key, custManagerDTO);
                }
            }
        }
    }

    /**
     * 处理并缓存客户经理或机构的统计结果
     *
     * @param key              Redis缓存key
     * @param custManagerDTO   查询条件DTO
     * @return 处理后的VO对象
     */
    private void processAndCacheResult(String key, CustManagerDTO custManagerDTO) {
        // 查出总资产余额、总资产余额较上月变动、总资产月日均
        DwbRetailResultVO vo = gridCmpmMapper.getCustManagerResult(custManagerDTO);
        if (vo.getCustAumMonthAvg() != null && vo.getCustAumMonthAvgLm() != null) {
            vo.setCustAumMonthAvgCompLm(vo.getCustAumMonthAvg().subtract(vo.getCustAumMonthAvgLm()));
        } else {
            vo.setCustAumMonthAvgCompLm(BigDecimal.ZERO);
        }
        if (vo.getCustAumBal() != null && vo.getAumBalCompLm() != null) {
            vo.setCustAumBalLm(vo.getCustAumBal().subtract(vo.getAumBalCompLm()));
        } else {
            vo.setCustAumBalLm(BigDecimal.ZERO);
        }
        // 获取当前各星级客户数
        Map<String, Integer> currentLevelCountMap = getCustLevelCountMap(custManagerDTO, "now");
        // 获取上月各星级客户数
        Map<String, Integer> historyLevelCountMap = getCustLevelCountMap(custManagerDTO, "last");
        Map<String, Integer> custLevelCompLm = calculateLevelChanges(historyLevelCountMap, currentLevelCountMap);

        // 在 vo.setCustLevelCompLm 之前，按顺序重新组织数据
        String[] order = {"5星", "4星", "3星", "2星", "1星", "基础", "长尾"};
        Map<String, Integer> orderedCustLevelCompLm = new LinkedHashMap<>();
        for (String itemKey : order) {
            if (custLevelCompLm.containsKey(itemKey)) {
                orderedCustLevelCompLm.put(itemKey, custLevelCompLm.get(itemKey));
            }
        }
        vo.setCustLevelCompLm(orderedCustLevelCompLm);
        // custLevelCount 同理
        Map<String, Integer> orderedCustLevelCount = new LinkedHashMap<>();
        for (String itemKey : order) {
            if (currentLevelCountMap.containsKey(itemKey)) {
                orderedCustLevelCount.put(itemKey, currentLevelCountMap.get(itemKey));
            }
        }
        vo.setCustLevelCount(orderedCustLevelCount);

        ObjectMapper objectMapper = new ObjectMapper();
        try{
            String json = objectMapper.writeValueAsString(vo);
            redisCache.setCacheObject(key, json, 31, TimeUnit.DAYS);
        }catch (Exception e){
            throw new ServiceException("JSON转换异常" + e.getMessage());
        }
    }


    private Map<String, Integer> getCustLevelCountMap(CustManagerDTO custManagerDTO, String time){
        List<String> custLevelList = gridCmpmMapper.getCustLevelList();
        //查出各星级客户数
        Map<String, Integer> custLevelCountMap = new HashMap<>();
        for (String custLevel : custLevelList) {
            custManagerDTO.setCustLevel(custLevel);
            int count = gridCmpmMapper.getCustCountByLevel(custManagerDTO, time);
            custLevelCountMap.put(custLevel, count);
        }
        return custLevelCountMap;
    }

    private void applyCustManagerScope(CustManagerDTO custManagerDTO) {
        String userRole = SecurityUtils.userRole();
        if (userRole.equals("manager")) {
            custManagerDTO.setManagerId(SecurityUtils.getUsername());
        } else if (userRole.equals("outlet")) {
            custManagerDTO.setOutletId(String.valueOf(SecurityUtils.getDeptId()));
        } else if (userRole.equals("branch")) {
            custManagerDTO.setBranchId(String.valueOf(SecurityUtils.getDeptId()));
        }
    }

    private void doExportCustManager(String taskId, CustManagerDTO custManagerDTO, String userName, String headId) {
        ImportExportTask task = importExportTaskMapper.selectById(taskId);
        File tempFile = null;
        try {
            tempFile = File.createTempFile("管户报表导出_" + taskId + "-", ".xlsx");
            ExcelWriter excelWriter = EasyExcel.write(tempFile, DwbRetailCustLevelManagerDetailVO.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("管户报表").build();
            int pageSize = 1000;
            int pageNum = 0;
            List<DwbRetailCustLevelManagerDetailVO> pageData;

            do {
                pageData = gridCmpmMapper.getCustManagerListByPage(custManagerDTO, headId, pageNum * pageSize, pageSize);
                if (!pageData.isEmpty()) {
                    excelWriter.write(pageData, writeSheet);
                }
                pageNum++;
            } while (pageData.size() == pageSize);

            excelWriter.finish();

            String ossUUId = ossFileService.uploadFileToOss(
                    OssFileEnum.CUST_MANAGER_REPORT,
                    tempFile,
                    "管户报表导出_" + taskId + ".xlsx",
                    userName
            );

            task.setStatus("1");
            task.setFileUrl(ossUUId);
            task.setFinishTime(new Date());
            importExportTaskMapper.updateById(task);
        } catch (Exception e) {
            task.setStatus("2");
            task.setFinishTime(new Date());
            task.setErrorMsg(e.getMessage());
            importExportTaskMapper.updateById(task);
        } finally {
            if (Objects.nonNull(tempFile)) {
                boolean deleted = tempFile.delete();
                if (!deleted) {
                    log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
                }
            }
        }
    }

    // 计算客户等级变化情况
    private Map<String, Integer> calculateLevelChanges(Map<String, Integer> historyMap, Map<String, Integer> currentMap) {
        Map<String, Integer> changesMap = new HashMap<>();

        if (historyMap == null) {
            // 如果没有历史数据，所有当前数据都是新增的
            for (Map.Entry<String, Integer> entry : currentMap.entrySet()) {
                changesMap.put(entry.getKey(), entry.getValue());
            }
            return changesMap;
        }
        // 计算每个等级的变化量（当前 - 历史 = 变化量）
        // 正数表示增加，负数表示减少
        for (String custLevel : currentMap.keySet()) {
            Integer currentCount = currentMap.getOrDefault(custLevel, 0);
            Integer historyCount = historyMap.getOrDefault(custLevel, 0);
            changesMap.put(custLevel, currentCount - historyCount);
        }

        // 处理历史数据中有但当前数据中没有的等级（这些等级的客户数变为0）
        for (String custLevel : historyMap.keySet()) {
            if (!currentMap.containsKey(custLevel)) {
                changesMap.put(custLevel, -historyMap.get(custLevel));
            }
        }
        return changesMap;
    }

    /**
     * 全量查询绩效网格客户列表（用于客群管户关系匹配，不依赖SecurityUtils）
     * @param gridType 网格类型
     * @param headId 总行ID
     * @return 客户列表（包含管户关系信息）
     */
    public List<GridCmpmVO> selectAllForImport(String gridType, String headId) {
        return gridCmpmMapper.getAllCustomerListForImport(gridType, headId);
    }

    /**
     * 根据客户ID列表查询管户关系（用于动态客群更新管户关系）
     * @param gridType 网格类型（retail/corporate）
     * @param headId 总行ID
     * @param custInfoList 客户信息列表（包含custId和custType）
     * @return 客户管户关系列表
     */
    public List<GridCmpmVO> getRelationshipsByCustList(String gridType, String headId, List<Map<String, String>> custInfoList) {
        if (custInfoList == null || custInfoList.isEmpty()) {
            return new ArrayList<>();
        }
        return gridCmpmMapper.getRelationshipsByCustList(gridType, headId, custInfoList);
    }

}
