package com.prolog.rdc.tms.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.product.core.easyexcel.util.ExcelUtils;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.product.core.tools.util.JsonMapper;
import com.prolog.product.core.tools.util.ToolKits;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.constant.RabbitMQConstant;
import com.prolog.rdc.tms.dao.mapper.SettlementFeeMapper;
import com.prolog.rdc.tms.model.dto.BmsSettlementFeeDTO;
import com.prolog.rdc.tms.model.dto.SettlementTypeDTO;
import com.prolog.rdc.tms.model.dto.basicConfigure.StandardTemplateDetailsListDTO;
import com.prolog.rdc.tms.model.entity.BmsSettlementFeeModel;
import com.prolog.rdc.tms.model.vo.BmsSettlementFeeQueryVO;
import com.prolog.rdc.tms.model.vo.BmsSettlementFeeVO;
import com.prolog.rdc.tms.model.vo.SettlementFeeImportVO;
import com.prolog.rdc.tms.model.vo.StatusUpdate;
import com.prolog.rdc.tms.model.vo.basicConfigure.ImportLogAddVO;
import com.prolog.rdc.tms.model.vo.basicData.SettlementTypeVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.SettlementFeeService;
import com.prolog.rdc.tms.util.FileUtils;
import com.prolog.rdc.tms.util.ImportUtils;
import org.apache.ibatis.plugin.PluginException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class SettlementFeeServiceImpl implements SettlementFeeService {

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

    @Autowired
    private SettlementFeeMapper mapper;
    @Autowired
    private MaindataFeign maindataTmsResource;
    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    public Page<BmsSettlementFeeDTO> findList(BmsSettlementFeeQueryVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Criteria criteria = Criteria.forClass(BmsSettlementFeeModel.class);
        Restriction r1 = ObjectUtil.isEmpty(vo.getAccountWayName()) ? null : Restrictions.like("accountWayName", "%" + vo.getAccountWayName() + "%");
        Restriction r2 = ObjectUtil.isEmpty(vo.getAccountWayCode()) ? null : Restrictions.like("accountWayCode", "%" + vo.getAccountWayCode() + "%");
        Restriction r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2,r3));
        criteria.setOrder(Order.newInstance().desc("updatetime").asc("createtime"));
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<BmsSettlementFeeModel> models = mapper.findByCriteria(criteria);

        List<BmsSettlementFeeDTO> list = Lists.newArrayList();
        for (BmsSettlementFeeModel model : models) {
            BmsSettlementFeeDTO dto = new BmsSettlementFeeDTO();
            BeanUtils.copyProperties(model, dto);
            dto.setStatusName(model.getStatus() == 1 ? "启用" : "停用");
            dto.setAccountTypeName(model.getAccountType() == 1 ? "到付" : "欠付");
            list.add(dto);
        }
        // 分页设置
        Page<BmsSettlementFeeDTO> page = PageUtils.getPage(list);
        if (models instanceof com.github.pagehelper.Page) {
            com.github.pagehelper.Page<BmsSettlementFeeModel> p0 = (com.github.pagehelper.Page<BmsSettlementFeeModel>) models;
            page.setPageCount(p0.getPages());
            page.setPageNum(p0.getPageNum());
            page.setPageSize(p0.getPageSize());
            page.setTotalCount(p0.getTotal());
            page.setStartRow(p0.getStartRow());
            page.setEndRow(p0.getEndRow());
        }
        return page;
    }

    @Override
    public List<BmsSettlementFeeDTO> findListNoPage(String code) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        List<BmsSettlementFeeDTO> list = Lists.newArrayList();
        if (ObjectUtil.isNotEmpty(code)) {
            RestMessage<List<SettlementTypeDTO>> message = this.findSettlement("",code,user);
            if (ObjectUtil.isNotEmpty(message) && ObjectUtil.isNotEmpty(message.getData())) {
                List<SettlementTypeDTO> settlementTypeDTOS = message.getData();
                for (SettlementTypeDTO settlementTypeDTO : settlementTypeDTOS) {
                    BmsSettlementFeeDTO model = new BmsSettlementFeeDTO();
                    BeanUtils.copyProperties(settlementTypeDTO,model);
                    model.setAccountTypeName(model.getAccountType() == 1 ? "到付" : "欠付");
                    list.add(model);
                }
            }
        } else {
            Criteria criteria = Criteria.forClass(BmsSettlementFeeModel.class);
            Restriction r1 = Restrictions.eq("status", 1);
            Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            criteria.setOrder(Order.newInstance().desc("updatetime").asc("createtime"));
            List<BmsSettlementFeeModel> models = mapper.findByCriteria(criteria);
            if (ObjectUtil.isNotEmpty(models)) {
                for (BmsSettlementFeeModel feeModel : models) {
                    BmsSettlementFeeDTO settlementFeeModel = new BmsSettlementFeeDTO();
                    BeanUtils.copyProperties(feeModel, settlementFeeModel);
                    settlementFeeModel.setAccountTypeName(settlementFeeModel.getAccountType() == 1 ? "到付" : "欠付");
                    list.add(settlementFeeModel);
                }
            }
        }
        return list;

    }

    private RestMessage<List<SettlementTypeDTO>> findSettlement(String accountWayCode,String code, UserEntity user) {
        SettlementTypeVO settlementTypeVO = new SettlementTypeVO();
        settlementTypeVO.setAccountWayCode(accountWayCode);
        settlementTypeVO.setCode(code);
        settlementTypeVO.setEnterpriseId(user.getEnterpriseId());
        return maindataTmsResource.getSettlementByCode(settlementTypeVO);
    }

    @Override
    public void importExpense(MultipartFile file) throws IOException {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        if (ObjectUtil.isEmpty(user)) {
            throw new PluginException("当前人员没有操作权限");
        }
        // 导入文件判断
        FileUtils.multipartFileJudge(file);
        // 导入批次
        RestMessage<String> code = maindataTmsResource.getCodeNumberByCode(BmsConstant.IMPORT_BATCHNO, "L");
        if (ObjectUtil.isEmpty(code.getData())) {
            throw new PluginException("获取批次ID失败");
        }
        // 导入日志对象
        ImportLogAddVO logAddVO = new ImportLogAddVO();
        logAddVO.setImportObjNo(BmsConstant.SETTLEMENT_FEE_IMPORT);
        logAddVO.setImportBatchNumber(code.getData());
        // 导入统计
        int count = 0;
        try {
            // 导入执行
            count = this.importProcess(file, code.getData(), user);
            logAddVO.setStatus(BmsConstant.IMPORT_STATUS_YES);
            logAddVO.setSuccessNum(count);
            logAddVO.setFailNum(0);
            maindataTmsResource.addImportLogExecute(logAddVO);
        } catch (Exception e) {
            Class<SettlementFeeImportVO> importVOClass = SettlementFeeImportVO.class;
            List<SettlementFeeImportVO> accountImportVOS = ExcelUtils.read(file, importVOClass);

            logAddVO.setStatus(BmsConstant.IMPORT_STATUS_NO);
            logAddVO.setSuccessNum(0);
            logAddVO.setFailNum(accountImportVOS.size());
            logAddVO.setFailReason(e.getMessage());
            // 为了避免导入失败时导入日志的保存事务也被回滚,所以采用消息队列异步保存导入失败的日志
            amqpTemplate.convertAndSend(RabbitMQConstant.SETTLEMENT_FEE_IMPORT, logAddVO);
            e.printStackTrace();
            throw new ParameterException(e.getMessage());
        }
    }

    private int importProcess(MultipartFile file, String data, UserEntity user) {
        Date date = new Date();
        // 商品资料对象集合
        List<BmsSettlementFeeModel> modelList = Lists.newArrayList();
        Properties properties = new Properties();
        // 待转换的对象
        Class<SettlementFeeImportVO> importVOClass = SettlementFeeImportVO.class;
        // 标准模板查询
        RestMessage<List<StandardTemplateDetailsListDTO>> restMessage = maindataTmsResource.listStandardTemplateDetailsExecute(BmsConstant.SETTLEMENT_FEE_IMPORT);
        if (!restMessage.isSuccess()) {
            throw new ParameterException("标准模板详情查询失败:" + restMessage.getMessage());
        }

        List<StandardTemplateDetailsListDTO> standardTemplateDetailsListDTOs = restMessage.getData();
        ToolKits.isParamNull(standardTemplateDetailsListDTOs, "运单标准模板未配置");

        for (StandardTemplateDetailsListDTO standardTemplateDetailsListDTO : standardTemplateDetailsListDTOs) {
            // 属性字段和注解属性字段值 键值对
            properties.setProperty(standardTemplateDetailsListDTO.getStdColNo(), standardTemplateDetailsListDTO.getCustColName());
        }
        // @ExcelProperty注解属性修改
        ImportUtils.setHeaderValue(properties, importVOClass);
        // EXCEL转对象
        List<SettlementFeeImportVO> accountImportVOS;
        try {
            accountImportVOS = ExcelUtils.read(file, importVOClass);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("EXCEL转对象失败:" + e.getMessage());
        }

        ToolKits.isParamNull(accountImportVOS, "EXCEL文件内容为空,请重新导入");

        int i = 1;
        for (SettlementFeeImportVO itemImportStdVO : accountImportVOS) {
            if (ToolKits.isEmpty(itemImportStdVO.getAccountWayCode())) {
                throw new PrologException("第" + i + "行导入数据,结算编码不能为空");
            }
            if (ToolKits.isEmpty(itemImportStdVO.getAccountWayName())) {
                throw new PrologException("第" + i + "行导入数据,结算名称不能为空");
            }
            if (ToolKits.isEmpty(itemImportStdVO.getAccountType())) {
                throw new PrologException("第" + i + "行导入数据,结算分类不能为空");
            }
            i++;
        }
        // 验证导入文件中费用编号是否重复
        Map<String, Long> codeMap = accountImportVOS.stream().collect(Collectors.groupingBy(SettlementFeeImportVO::getAccountWayCode, Collectors.counting()));
        for (Map.Entry<String, Long> longEntry : codeMap.entrySet()) {
            if (longEntry.getValue() > 1) {
                throw new BizException(String.format("导入文件中，费用编号[%s]重复", longEntry.getKey()));
            }
        }
        // 验证导入文件中费用名称是否重复
        Map<String, Long> nameMap = accountImportVOS.stream().collect(Collectors.groupingBy(SettlementFeeImportVO::getAccountWayName, Collectors.counting()));
        for (Map.Entry<String, Long> longEntry : nameMap.entrySet()) {
            if (longEntry.getValue() > 1) {
                throw new ParameterException(String.format("导入文件中，费用名称[%s]重复", longEntry.getKey()));
            }
        }
        AtomicInteger num = new AtomicInteger(0);
        for (SettlementFeeImportVO itemImportStdVO : accountImportVOS) {
            // 费用科目
            BmsSettlementFeeModel expenseAccountModel = new BmsSettlementFeeModel();
            BeanUtils.copyProperties(itemImportStdVO, expenseAccountModel);
            expenseAccountModel.setCreatetime(date);
            expenseAccountModel.setCreateperson(user.getNickname());
            expenseAccountModel.setUpdateperson(user.getNickname());
            expenseAccountModel.setUpdatetime(date);
            expenseAccountModel.setEnterpriseId(user.getEnterpriseId());
            expenseAccountModel.setEnterpriseName(user.getEnterpriseName());
            expenseAccountModel.setAccountType(Integer.parseInt(itemImportStdVO.getAccountType()));
            expenseAccountModel.setStatus(1);
            mapper.save(expenseAccountModel);

            modelList.add(expenseAccountModel);

            num.getAndIncrement();
        }
        return modelList.size();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(BmsSettlementFeeVO vo) {
        logger.info("新增结算信息：" + JSONObject.toJSONString(vo));
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        //2 判断流程是否已配置
        Criteria criteria = Criteria.forClass(BmsSettlementFeeModel.class);
        Restriction r1 = Restrictions.eq("accountWayName", vo.getAccountWayName().trim());
        Restriction r2 = Restrictions.eq("accountWayCode", vo.getAccountWayCode().trim());
        Restriction r4 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        Restriction r3 = Restrictions.or(r1, r2);
        criteria.setRestriction(Restrictions.and(r3,r4));
        List<BmsSettlementFeeModel> list = mapper.findByCriteria(criteria);
        if (ObjectUtil.isNotEmpty(list) && list.size() > 0) {
            throw new RuntimeException("结算费用已经存在，请不要重复提交");
        }
        BmsSettlementFeeModel model = new BmsSettlementFeeModel();
        BeanUtils.copyProperties(vo, model);
        model.setCreateperson(user.getNickname());
        model.setCreatetime(DateUtil.date());
        model.setUpdateperson(user.getNickname());
        model.setUpdatetime(DateUtil.date());
        model.setEnterpriseId(user.getEnterpriseId());
        model.setEnterpriseName(user.getEnterpriseName());
        mapper.save(model);

    }

    @Override
    public BmsSettlementFeeDTO detail(Long id) {
        if (ObjectUtil.isEmpty(id)) {
            throw new PluginException("查询条件不能为空");
        }
        BmsSettlementFeeModel strategyModel = mapper.findById(id, BmsSettlementFeeModel.class);
        if (ObjectUtil.isEmpty(strategyModel)) {
            throw new PluginException("获取比例策略为空");
        }
        BmsSettlementFeeDTO strategyDTO = new BmsSettlementFeeDTO();
        BeanUtils.copyProperties(strategyModel,strategyDTO);
        strategyDTO.setAccountTypeName(strategyModel.getAccountType() == 1 ? "到付" : "欠付");
        return strategyDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(BmsSettlementFeeVO vo) {
        if (ObjectUtil.isEmpty(vo.getId())) {
            throw new PluginException("修改参数不能为空");
        }
        BmsSettlementFeeModel model = mapper.findById(vo.getId(), BmsSettlementFeeModel.class);
        if (ObjectUtil.isEmpty(model)) {
            throw new PluginException("查询结算数据不存在");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        BeanUtils.copyProperties(vo, model);
        model.setUpdateperson(user.getNickname());
        model.setUpdatetime(DateUtil.date());
        mapper.update(model);

    }

    @Override
    public void updateStatus(List<StatusUpdate> vo) {
        logger.info("- > updateStatus vo={}", JsonMapper.toJsonString(vo));
        // 1 校验数据
        if (ObjectUtil.isEmpty(vo)) {
            throw new RuntimeException("请求参数不能为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        for (StatusUpdate statusUpdate : vo) {
            BmsSettlementFeeModel model = mapper.findById(statusUpdate.getId(), BmsSettlementFeeModel.class);
            model.setStatus(statusUpdate.getStatus());
            model.setUpdateperson(user.getNickname());
            model.setUpdatetime(DateUtil.date());
            mapper.update(model);
        }
    }

    @Override
    public void delete(String[] ids) {
        if (ObjectUtil.isEmpty(ids)) {
            throw new RuntimeException("请求参数不能为空");
        }
        // 判断是否启用
        for (String id : ids) {
            BmsSettlementFeeModel model = mapper.findById(id, BmsSettlementFeeModel.class);
            if (model.getStatus() == 1) {
                throw new PluginException(String.format("结算名称[%s],是启用状态不能删除", model.getAccountWayName()));
            }

            mapper.deleteById(id, BmsSettlementFeeModel.class);
        }
    }
}