package com.simuwang.manage.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
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.StringUtil;
import com.simuwang.base.mapper.AssetMapper;
import com.simuwang.base.mapper.FundInfoMapper;
import com.simuwang.base.mapper.FundNavAssetMapper;
import com.simuwang.base.mapper.NavMapper;
import com.simuwang.base.pojo.dos.AssetDO;
import com.simuwang.base.pojo.dos.FundNavAssetDO;
import com.simuwang.base.pojo.dos.NavDO;
import com.simuwang.base.pojo.dto.DistributionExcelData;
import com.simuwang.base.pojo.dto.NavAssetExcelData;
import com.simuwang.base.pojo.dto.query.FundNavAssetPageQuery;
import com.simuwang.base.pojo.vo.*;
import com.simuwang.manage.service.FundNavAssetService;
import com.smppw.common.pojo.ResultVo;
import com.smppw.common.pojo.enums.status.ResultCode;
import org.apache.commons.io.FileUtils;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * FileName: FundNavAssetServiceImpl
 * Author:   chenjianhua
 * Date:     2024/9/15 16:58
 * Description: ${DESCRIPTION}
 */
@Service
public class FundNavAssetServiceImpl implements FundNavAssetService {
    @Autowired
    private FundNavAssetMapper fundNavAssetMapper;

    @Autowired
    private AssetMapper assetMapper;

    @Autowired
    private NavMapper navMapper;

    @Autowired
    private FundInfoMapper fundInfoMapper;

    @Value("${email.file.path}")
    private String path;
    private static final Logger logger = LoggerFactory.getLogger(FundNavAssetServiceImpl.class);
    @Override
    public MybatisPage<FundNavAssetVO> searchNavAssetList(FundNavAssetPageQuery fundNavAssetPageQuery) {
        List<FundNavAssetDO> fundNavAssetDOList = fundNavAssetMapper.searchNavAssetList(fundNavAssetPageQuery);
        List<FundNavAssetVO> fundNavAssetVOList = fundNavAssetDOList.stream().map(FundNavAssetDO::toVo).collect(Collectors.toList());
        long total = fundNavAssetMapper.countNavAssetList(fundNavAssetPageQuery);
        return MybatisPage.of(total,fundNavAssetVOList);
    }


    @Override
    public void saveFundAsset(FundAssetVO fundAssetVO) {
        List<AssetDO> assetDOList = new ArrayList<>();
        AssetDO assetDO = new AssetDO();
        assetDO.setAssetNet(fundAssetVO.getAssetNet());
        assetDO.setAssetShare(fundAssetVO.getAssetShare());
        assetDO.setPriceDate(DateUtils.parse(fundAssetVO.getPriceDate(),DateUtils.YYYY_MM_DD));
        assetDO.setFundId(fundAssetVO.getFundId());
        assetDO.setUpdateTime(DateUtils.getNowDate());
        assetDO.setIsvalid(1);
        AssetDO oldAssetDO = assetMapper.queryFundAsset(assetDO);
        if(StringUtil.isNull(oldAssetDO)){
            assetDO.setCreateTime(DateUtils.getNowDate());
            assetDOList.add(assetDO);
            assetMapper.batchInsert(assetDOList);
        }else{
            oldAssetDO.setAssetShare(assetDO.getAssetShare());
            oldAssetDO.setAssetNet(assetDO.getAssetNet());
            assetDOList.add(oldAssetDO);
            assetMapper.batchUpdate(assetDOList);
        }
    }

    @Override
    public void saveFundNav(FundNavVO fundNavVO) {
        List<NavDO> navDOList = new ArrayList<>();
        NavDO navDO = new NavDO();
        navDO.setCumulativeNavWithdrawal(fundNavVO.getCumulativeNavWithdrawal());
        navDO.setNav(fundNavVO.getNav());
        navDO.setFundId(fundNavVO.getFundId());
        navDO.setNav(fundNavVO.getNav());
        navDO.setPriceDate(DateUtils.parse(fundNavVO.getPriceDate(),DateUtils.YYYY_MM_DD));
        navDO.setIsvalid(1);
        navDO.setUpdateTime(DateUtils.getNowDate());
        NavDO oldNav = navMapper.queryFundNav(navDO);
        if(StringUtil.isNull(oldNav)){
            navDO.setCreateTime(DateUtils.getNowDate());
            navDOList.add(navDO);
            navMapper.batchInsert(navDOList);
        }else{
            oldNav.setUpdateTime(DateUtils.getNowDate());
            oldNav.setCumulativeNav(navDO.getCumulativeNav());
            oldNav.setCumulativeNavWithdrawal(navDO.getCumulativeNavWithdrawal());
            oldNav.setNav(navDO.getNav());
            navDOList.add(oldNav);
            navMapper.batchUpdate(navDOList);
        }
    }

    @Override
    public void deleteFundNavAsset(FundNavAssetDelListVO fundNavAssetDelListVO) {
        List<FundNavAssetDelVO> delVOList = fundNavAssetDelListVO.getFundNavAssetDelVOList();
        for(FundNavAssetDelVO delVO : delVOList){
            navMapper.deleteNav(delVO.getFundId(),delVO.getPriceDate());
            assetMapper.deleteAsset(delVO.getFundId(),delVO.getPriceDate());
        }
    }

    @Override
    public ResultVo uploadNavAsset(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<NavAssetExcelData> 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<NavAssetExcelData> list) {
        Map<String,Object> result = new HashMap<>();
        int startRow = 3;
        List<ExcelNavAssetSuccessDataVO> successDataVOList = new ArrayList<>();
        List<ExcelNavAssetFailDataVO> excelFailDataVOList = new ArrayList<>();
        for(int dataIdx=1;dataIdx<list.size(); dataIdx++){
            NavAssetExcelData excelData = list.get(dataIdx);
            try{
                if((StringUtil.isEmpty(excelData.getFundName()) && StringUtil.isEmpty(excelData.getFundId()))
                        || StringUtil.isEmpty(excelData.getPriceDate())){
                    ExcelNavAssetFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.REQUIRE_FIELD,dataIdx+startRow);
                    excelFailDataVOList.add(failDataVO);
                    continue;
                }
                if(StringUtil.isNotEmpty(excelData.getFundId())){
                    String fundName = fundInfoMapper.getFundNameByFundId(excelData.getFundId());
                    if(StringUtil.isEmpty(fundName)){
                        ExcelNavAssetFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.NOT_MAPPING_FUND,dataIdx+startRow);
                        excelFailDataVOList.add(failDataVO);
                        continue;
                    }
                }else{
                    String fundId = fundInfoMapper.queryFundIdByName(excelData.getFundName());
                    if(StringUtil.isEmpty(fundId)){
                        ExcelNavAssetFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.NOT_MAPPING_FUND,dataIdx+startRow);
                        excelFailDataVOList.add(failDataVO);
                        continue;
                    }else{
                        excelData.setFundId(fundId);
                    }
                }
                if(StringUtil.isEmpty(excelData.getNav()) || Double.valueOf(excelData.getNav()) < 0){
                    ExcelNavAssetFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.ERROR_NAV,dataIdx+startRow);
                    excelFailDataVOList.add(failDataVO);
                    continue;
                }
                if(StringUtil.isEmpty(excelData.getCumulativeNavWithdrawal()) || Double.valueOf(excelData.getCumulativeNavWithdrawal()) < 0){
                    ExcelNavAssetFailDataVO failDataVO = toExcelFailDataVO(excelData,ExcelConst.ERROR_NAV_WITHDRAWAL,dataIdx+startRow);
                    excelFailDataVOList.add(failDataVO);
                    continue;
                }
                //开始处理成功数据
                FundNavVO fundNavVO = new FundNavVO();
                fundNavVO.setFundId(excelData.getFundId());
                fundNavVO.setPriceDate(excelData.getPriceDate());
                fundNavVO.setNav(BigDecimal.valueOf(Double.valueOf(excelData.getNav())));
                fundNavVO.setCumulativeNavWithdrawal(BigDecimal.valueOf(Double.valueOf(excelData.getCumulativeNavWithdrawal())));
                saveFundNav(fundNavVO);
                if(StringUtil.isEmpty(excelData.getAssetNet()) && StringUtil.isEmpty(excelData.getAssetShare())){
                    continue;
                }
                FundAssetVO fundAssetVO = new FundAssetVO();
                fundAssetVO.setFundId(excelData.getFundId());
                fundAssetVO.setPriceDate(excelData.getPriceDate());
                fundAssetVO.setAssetNet(StringUtil.isEmpty(excelData.getAssetNet())?null:BigDecimal.valueOf(Double.valueOf(excelData.getAssetNet())));
                fundAssetVO.setAssetShare(StringUtil.isEmpty(excelData.getAssetShare())?null:BigDecimal.valueOf(Double.valueOf(excelData.getAssetShare())));
                saveFundAsset(fundAssetVO);
                //处理成功结果
                ExcelNavAssetSuccessDataVO excelNavAssetSuccessDataVO = new ExcelNavAssetSuccessDataVO();
                excelNavAssetSuccessDataVO.setFundName(excelData.getFundName());
                excelNavAssetSuccessDataVO.setPriceDate(excelData.getPriceDate());
                excelNavAssetSuccessDataVO.setNav(excelData.getNav());
                excelNavAssetSuccessDataVO.setCumulativeNavWithdrawal(excelData.getCumulativeNavWithdrawal());
                excelNavAssetSuccessDataVO.setAssetNet(excelData.getAssetNet());
                excelNavAssetSuccessDataVO.setAssetShare(excelData.getAssetShare());
                successDataVOList.add(excelNavAssetSuccessDataVO);
            }catch (Exception e){
                logger.error(e.getMessage(),e);
                ExcelNavAssetFailDataVO failDataVO = toExcelFailDataVO(excelData,e.getMessage(),dataIdx+startRow);
                excelFailDataVOList.add(failDataVO);
            }
        }
        result.put("success",successDataVOList);
        result.put("fail",excelFailDataVOList);
        return result;
    }

    private ExcelNavAssetFailDataVO toExcelFailDataVO(NavAssetExcelData excelData, String msg, int runNum) {
        ExcelNavAssetFailDataVO failDataVO = new ExcelNavAssetFailDataVO();
        failDataVO.setFailReason(msg);
        failDataVO.setRowNum(runNum);
        failDataVO.setFundName(excelData.getFundName());
        failDataVO.setPriceDate(excelData.getPriceDate());
        failDataVO.setNav(excelData.getNav());
        failDataVO.setCumulativeNavWithdrawal(excelData.getCumulativeNavWithdrawal());
        return failDataVO;
    }

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