package com.simuwang.manage.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.simuwang.base.common.conts.DateConst;
import com.simuwang.base.common.conts.ExcelConst;
import com.simuwang.base.common.enums.DistributeType;
import com.simuwang.base.common.support.MybatisPage;
import com.simuwang.base.common.util.DateUtils;
import com.simuwang.base.common.util.ExcelUtil;
import com.simuwang.base.common.util.FileUtil;
import com.simuwang.base.common.util.StringUtil;
import com.simuwang.base.mapper.DistributionMapper;
import com.simuwang.base.mapper.FundInfoMapper;
import com.simuwang.base.mapper.NavMapper;
import com.simuwang.base.pojo.dos.DistributionDO;
import com.simuwang.base.pojo.dos.DistributionTablePageDO;
import com.simuwang.base.pojo.dos.FundInfoDO;
import com.simuwang.base.pojo.dos.NavDO;
import com.simuwang.base.pojo.dto.DistributionExcelData;
import com.simuwang.base.pojo.dto.query.DistributionPageQuery;
import com.simuwang.base.pojo.vo.*;
import com.simuwang.manage.service.DistributionService;
import com.smppw.common.pojo.ResultVo;
import com.smppw.common.pojo.enums.status.ResultCode;
import com.smppw.common.pojo.enums.status.StatusCode;
import org.apache.commons.io.FileUtils;
import org.apache.poi.ss.formula.functions.Na;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * FileName: DistributionServiceImpl
 * Author:   chenjianhua
 * Date:     2024/9/15 14:07
 * Description: ${DESCRIPTION}
 */
@Service
public class DistributionServiceImpl implements DistributionService {

    private static final Logger logger = LoggerFactory.getLogger(DistributionServiceImpl.class);


    @Autowired
    private DistributionMapper distributionMapper;

    @Autowired
    private NavMapper navMapper;

    @Autowired
    private FundInfoMapper fundInfoMapper;

    @Value("${email.file.path}")
    private String path;
    @Override
    public MybatisPage<DistributionTablePageVO> searchDistributionList(DistributionPageQuery distributionPageQuery) {
        List<DistributionTablePageDO> distributionTablePageDOList = distributionMapper.searchDistributionList(distributionPageQuery);
        List<DistributionTablePageVO> distributionTablePageVOList = distributionTablePageDOList.stream().map(DistributionTablePageDO::toVo).collect(Collectors.toList());
        long total = distributionMapper.countDistributionList(distributionPageQuery);
        return MybatisPage.of(total,distributionTablePageVOList);
    }

    @Override
    public ResultVo saveDistribution(DistributionVO distributionVO) {
        ResultVo vo = new ResultVo(true);
        DistributionDO distributionDO = new DistributionDO();
        distributionDO.setFundId(distributionVO.getFundId());
        distributionDO.setDistribution(distributionVO.getDistribution());
        distributionDO.setDistributeDate(DateUtils.parse(distributionVO.getDistributeDate(),DateUtils.YYYY_MM_DD));
        distributionDO.setDistributeType(distributionVO.getDistributeType());
        distributionDO.setIsvalid(1);
        distributionDO.setUpdateTime(DateUtils.getNowDate());
        DistributionDO oldDistributionDO = distributionMapper.selectDistributionByDate(distributionVO.getFundId(),DateUtils.parse(distributionVO.getDistributeDate(),DateUtils.YYYY_MM_DD));
        if(!StringUtil.isNull(oldDistributionDO)){
            if(distributionVO.getId() != null && !oldDistributionDO.getId().equals(distributionVO.getId())){
                vo.setData(false);
                vo.setMsg("同一基金在同一天不能已存在分红数据");
                return vo;
            }
            distributionDO.setId(oldDistributionDO.getId());
            distributionMapper.updateDistributionById(distributionDO);
        }else{
            distributionDO.setCreateTime(DateUtils.getNowDate());
            distributionMapper.saveDistribution(distributionDO);
        }
        if(distributionVO.getNav() == null){
            return vo;
        }
        //保存净值
        NavDO navDO = new NavDO();
        navDO.setFundId(distributionVO.getFundId());
        navDO.setNav(distributionVO.getNav());
        navDO.setCumulativeNavWithdrawal(distributionVO.getCumulativeNavWithdrawal());
        navDO.setPriceDate(DateUtils.parse(distributionVO.getDistributeDate(),DateUtils.YYYY_MM_DD));
        NavDO oldNav = navMapper.queryFundNav(navDO);
        if(StringUtil.isNull(oldNav)){
            navDO.setUpdateTime(DateUtils.getNowDate());
            navDO.setCreateTime(DateUtils.getNowDate());
            navDO.setIsvalid(1);
            navMapper.saveNav(navDO);
        }else{
            navDO.setId(oldNav.getId());
            navDO.setUpdateTime(DateUtils.getNowDate());
            navMapper.updateNav(navDO);
        }
        return vo;
    }

    @Override
    public void deleteDistribution(IdListVO idListVO) {
        distributionMapper.deleteDistribution(idListVO.getIdList());
    }

    @Override
    public ResultVo uploadDistribution(MultipartFile excelFile) {
        ResultVo vo = new ResultVo(ResultCode.SUCCESS);
        File file = null;
        try{
            InputStream inputStream = excelFile.getInputStream();
            file = new File(path+"/upload/"+ System.currentTimeMillis()+"/"+excelFile.getOriginalFilename());
            FileUtils.copyInputStreamToFile(inputStream,file);
            List<DistributionExcelData> list = parseDistributionFile(file);
            vo.setData(parseResult(list));
        }catch (Exception e){
            logger.error(e.getMessage(),e);
            vo.setMsg("文件解析异常");
            vo.setData(false);
            return vo;
        }

        return vo;
    }

    private Map<String,Object> parseResult(List<DistributionExcelData> list) {
        Map<String,Object> result = new HashMap<>();
        int startRow = 3;
        List<ExcelSuccessDataVO> successDataVOList = new ArrayList<>();
        List<ExcelFailDataVO> excelFailDataVOList = new ArrayList<>();
        for(int dataIdx=1;dataIdx<list.size(); dataIdx++){
            DistributionExcelData excelData = list.get(dataIdx);
            try{
                if((StringUtil.isEmpty(excelData.getFundName()) && StringUtil.isEmpty(excelData.getFundId()))
                        || StringUtil.isEmpty(excelData.getPriceDate()) || StringUtil.isEmpty(excelData.getNav())
                        || StringUtil.isEmpty(excelData.getDistributeType()) || StringUtil.isEmpty(excelData.getDistribution())
                        || StringUtil.isEmpty(excelData.getCumulativeNavWithdrawal())){
                    ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.REQUIRE_FIELD,dataIdx+startRow);
                    excelFailDataVOList.add(failDataVO);
                    continue;
                }
                if(excelData.getDistributeType().trim().equals(ExcelConst.CASH_DIVIDENDS)){
                    if(Double.valueOf(excelData.getDistribution()) < 0f){
                        ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.CASH_DIVIDENDS_FAIL,dataIdx+startRow);
                        excelFailDataVOList.add(failDataVO);
                        continue;
                    }
                }else{
                    if(Double.valueOf(excelData.getDistribution()) == 0f){
                        ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.DIVIDENDS_SPLIT_FAIL,dataIdx+startRow);
                        excelFailDataVOList.add(failDataVO);
                        continue;
                    }
                }
                if(StringUtil.isNotEmpty(excelData.getFundId())){
                    String fundName = fundInfoMapper.getFundNameByFundId(excelData.getFundId());
                    if(StringUtil.isEmpty(fundName)){
                        ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.NOT_MAPPING_FUND,dataIdx+startRow);
                        excelFailDataVOList.add(failDataVO);
                        continue;
                    }
                }else{
                    String fundId = fundInfoMapper.queryFundIdByName(excelData.getFundName());
                    if(StringUtil.isEmpty(fundId)){
                        ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.NOT_MAPPING_FUND,dataIdx+startRow);
                        excelFailDataVOList.add(failDataVO);
                        continue;
                    }else{
                        excelData.setFundId(fundId);
                    }
                }
                //开始处理成功数据
                DistributionVO distributionVO = new DistributionVO();
                distributionVO.setFundId(excelData.getFundId());
                distributionVO.setDistributeDate(excelData.getPriceDate());
                distributionVO.setDistributeType(DistributeType.getDistributeTypeByInfo(excelData.getDistributeType()).getCode());
                distributionVO.setDistribution(BigDecimal.valueOf(Double.valueOf(excelData.getDistribution())));
                distributionVO.setNav(BigDecimal.valueOf(Double.valueOf(excelData.getNav())));
                distributionVO.setCumulativeNavWithdrawal(BigDecimal.valueOf(Double.valueOf(excelData.getCumulativeNavWithdrawal())));
                ResultVo vo = saveDistribution(distributionVO);
                if((boolean)vo.getData() == true){
                    ExcelSuccessDataVO successDataVO = new ExcelSuccessDataVO();
                    successDataVO.setDistribution(excelData.getDistribution());
                    successDataVO.setFundName(excelData.getFundName());
                    successDataVO.setPriceDate(excelData.getPriceDate());
                    successDataVO.setDistributeType(excelData.getDistributeType());
                    successDataVOList.add(successDataVO);
                }else{
                    ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,vo.getMsg(),dataIdx+startRow);
                    excelFailDataVOList.add(failDataVO);
                }
            }catch (Exception e){
                logger.error(e.getMessage(),e);
                ExcelFailDataVO failDataVO = toExcelFailDataVO(excelData,e.getMessage(),dataIdx+startRow);
                excelFailDataVOList.add(failDataVO);
            }
        }
        result.put("success",successDataVOList);
        result.put("fail",excelFailDataVOList);
        return result;
    }

    private ExcelFailDataVO toExcelFailDataVO(DistributionExcelData excelData, String msg,Integer rowNum) {
        ExcelFailDataVO failDataVO = new ExcelFailDataVO();
        failDataVO.setFailReason(msg);
        failDataVO.setRowNum(rowNum);
        failDataVO.setDistribution(excelData.getDistribution());
        failDataVO.setFundName(excelData.getFundName());
        failDataVO.setPriceDate(excelData.getPriceDate());
        failDataVO.setDistributeType(excelData.getDistributeType());
        return failDataVO;
    }

    private List<DistributionExcelData> parseDistributionFile(File file) {
        // 创建一个 list 存储每行的数据，即 ExcelData 对象
        List<DistributionExcelData> list = new ArrayList<>();
        // 直接使用 EasyExcel 的 read 方法，同时定义表头的类型，以便将列中数据映射为 ExcelData 对象
        EasyExcel.read(file, DistributionExcelData.class, new PageReadListener<DistributionExcelData>(dataList -> {
            // 并且每行数据，并将其 add 至 list 中
            for (DistributionExcelData excelData : dataList) {
                if (excelData != null) {
                    list.add(excelData);
                }
            }
        })).excelType(ExcelTypeEnum.XLSX).sheet().doRead();
        return list;
    }
}
