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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
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.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.product.core.tools.util.JsonMapper;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.dao.mapper.TimeBillStrategyLadderMapper;
import com.prolog.rdc.tms.dao.mapper.TimeBillStrategyMapper;
import com.prolog.rdc.tms.model.dto.BmsTimeBillStrategyDTO;
import com.prolog.rdc.tms.model.dto.BmsTimeStrategyLadderDTO;
import com.prolog.rdc.tms.model.entity.BmsTimeBillStrategyLadderModel;
import com.prolog.rdc.tms.model.entity.BmsTimeBillStrategyModel;
import com.prolog.rdc.tms.model.entity.SysRefdatadModel;
import com.prolog.rdc.tms.model.vo.BmsTimeStrategyLadderVO;
import com.prolog.rdc.tms.model.vo.BmsTimeStrategyQueryVO;
import com.prolog.rdc.tms.model.vo.BmsTimeStrategyVO;
import com.prolog.rdc.tms.model.vo.StatusUpdate;
import com.prolog.rdc.tms.service.TimeBillStrategyService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import org.apache.ibatis.plugin.PluginException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class TimeBillStrategyServiceImpl implements TimeBillStrategyService {

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

    @Autowired
    private TimeBillStrategyMapper mapper;

    @Autowired
    private TimeBillStrategyLadderMapper ladderMapper;

    @Autowired
    private ConvertorUtil convertorUtil;

    @Override
    public Page<BmsTimeBillStrategyDTO> findList(BmsTimeStrategyQueryVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Criteria criteria = Criteria.forClass(BmsTimeBillStrategyModel.class);
        Restriction r1 = ObjectUtil.isEmpty(vo.getStrategyName()) ? null : Restrictions.like("strategyName", "%" + vo.getStrategyName() + "%");
        Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        criteria.setOrder(Order.newInstance().desc("updatetime"));
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<BmsTimeBillStrategyModel> models = mapper.findByCriteria(criteria);

        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.OMS_START_DATE_STRATEGY,
                BmsConstant.WEIGHT_INTEGER,
                BmsConstant.OMS_END_DATE_STRATEGY
        });

        List<BmsTimeBillStrategyDTO> list = Lists.newArrayList();
        for (BmsTimeBillStrategyModel model : models) {
            BmsTimeBillStrategyDTO dto = new BmsTimeBillStrategyDTO();
            BeanUtils.copyProperties(model, dto);

            dto.setTimeInteger(model.getTimeInteger());
            dto.setTimePrecision(model.getTimePrecision());

            dto.setStatusName(model.getStatus() == 1 ? "启用" : "停用");
            dto.setStartDateName(ConvertorUtil.getName(dicData, BmsConstant.OMS_START_DATE_STRATEGY, String.valueOf(model.getStartDate())));
            dto.setEndDateName(ConvertorUtil.getName(dicData, BmsConstant.OMS_END_DATE_STRATEGY, String.valueOf(model.getEndDate())));
            dto.setTimeIntegerName(ConvertorUtil.getName(dicData, BmsConstant.WEIGHT_INTEGER, String.valueOf(model.getTimeInteger())));
            if (ObjectUtil.isNotEmpty(model.getTimeLadderEnable())) {
                dto.setTimeLadderEnableName(NumberUtil.compare(model.getTimeLadderEnable(), 1) == 0 ? "启用" : "不启用");
            }
            list.add(dto);
        }
        // 分页设置
        Page<BmsTimeBillStrategyDTO> page = PageUtils.getPage(list);
        if (models instanceof com.github.pagehelper.Page) {
            com.github.pagehelper.Page<BmsTimeBillStrategyModel> p0 = (com.github.pagehelper.Page<BmsTimeBillStrategyModel>) 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
    @Transactional(rollbackFor = Exception.class)
    public void save(BmsTimeStrategyVO vo) {
        logger.info("新增时间策略信息：" + JSONObject.toJSONString(vo));
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        //2 判断流程是否已配置
        Criteria criteria = Criteria.forClass(BmsTimeBillStrategyModel.class);
        Restriction r1 = Restrictions.eq("strategyName", vo.getStrategyName().trim());
        Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsTimeBillStrategyModel> list = mapper.findByCriteria(criteria);
        if (ObjectUtil.isNotEmpty(list) && list.size() > 0) {
            throw new RuntimeException(String.format("时间策略名称【%s】已经存在，请不要重复提交", vo.getStrategyName()));
        }
        BmsTimeBillStrategyModel model = new BmsTimeBillStrategyModel();
        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());
        model.setStatus(1);
        model.setTimeInteger(vo.getTimeInteger());
        model.setTimePrecision(vo.getTimePrecision());
        model.setTimeLadderEnable(vo.getTimeLadderEnable());
        mapper.save(model);

        list = mapper.findByCriteria(criteria);

        List<BmsTimeStrategyLadderVO> timeStrategyLadderVOList = vo.getTimeStrategyLadderVOS();
        if (ObjectUtil.isNotEmpty(timeStrategyLadderVOList)) {
            List<BmsTimeBillStrategyLadderModel> timeBillStrategyLadderModels = Lists.newArrayList();
            long size  = timeStrategyLadderVOList.stream().filter(time->ObjectUtil.isEmpty(time.getLadderTime()) || NumberUtil.isLessOrEqual(time.getLadderTime(), BigDecimal.ZERO)).collect(Collectors.toList()).size();
            if (size > 0) {
                throw new PrologException("计费时间不为空");
            }
            for (BmsTimeStrategyLadderVO ladderVO : timeStrategyLadderVOList) {
                BmsTimeBillStrategyLadderModel ladderModel = new BmsTimeBillStrategyLadderModel();
                ladderModel.setId(null);
                ladderModel.setTimeStrategyId(list.get(0).getId());
                ladderModel.setSectionUp(ladderVO.getSectionUp());
                ladderModel.setSectionUpSymbol(ladderVO.getSectionUpSymbol());
                ladderModel.setSectionDown(ladderVO.getSectionDown());
                ladderModel.setSectionDownSymbol(ladderVO.getSectionDownSymbol());
                ladderModel.setLadderTime(ladderVO.getLadderTime());
                ladderModel.setCreateperson(user.getNickname());
                ladderModel.setCreatetime(DateUtil.date());
                ladderModel.setUpdateperson(user.getNickname());
                ladderModel.setUpdatetime(DateUtil.date());
                ladderModel.setEnterpriseId(user.getEnterpriseId());
                ladderModel.setEnterpriseName(user.getEnterpriseName());
                timeBillStrategyLadderModels.add(ladderModel);
            }
            ladderMapper.saveBatch(timeBillStrategyLadderModels);
        }
    }

    @Override
    public BmsTimeBillStrategyDTO detail(Long id) {
        if (ObjectUtil.isEmpty(id)) {
            throw new PluginException("查询条件不能为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        BmsTimeBillStrategyModel strategyModel = mapper.findById(id, BmsTimeBillStrategyModel.class);
        if (ObjectUtil.isEmpty(strategyModel)) {
            throw new PluginException("获取时间策略为空");
        }
        BmsTimeBillStrategyDTO strategyDTO = new BmsTimeBillStrategyDTO();
        BeanUtils.copyProperties(strategyModel, strategyDTO);

        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.OMS_START_DATE_STRATEGY,
                BmsConstant.SECTION_SYMBOL,
                BmsConstant.LESS_THAN,
                BmsConstant.WEIGHT_INTEGER,
                BmsConstant.OMS_END_DATE_STRATEGY
        });
        strategyDTO.setTimeInteger(strategyModel.getTimeInteger());
        strategyDTO.setTimePrecision(strategyModel.getTimePrecision());
        strategyDTO.setTimeLadderEnable(strategyModel.getTimeLadderEnable());
        strategyDTO.setStartDateName(ConvertorUtil.getName(dicData, BmsConstant.OMS_START_DATE_STRATEGY, String.valueOf(strategyModel.getStartDate())));
        strategyDTO.setEndDateName(ConvertorUtil.getName(dicData, BmsConstant.OMS_END_DATE_STRATEGY, String.valueOf(strategyModel.getEndDate())));
        strategyDTO.setTimeIntegerName(ConvertorUtil.getName(dicData, BmsConstant.WEIGHT_INTEGER, String.valueOf(strategyModel.getTimeInteger())));

        if (strategyModel.getTimeLadderEnable().intValue() == 1) {
            Criteria criteria = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
            Restriction r1 = Restrictions.eq(BmsTimeBillStrategyLadderModel::getTimeStrategyId, strategyModel.getId());
            Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            List<BmsTimeBillStrategyLadderModel> ladderModels = ladderMapper.findByCriteria(criteria);

            if (ObjectUtil.isNotEmpty(ladderModels)) {
                List<BmsTimeStrategyLadderDTO> ladderDTOS = Lists.newArrayList();
                for (BmsTimeBillStrategyLadderModel ladderModel : ladderModels) {
                    BmsTimeStrategyLadderDTO ladderDTO = new BmsTimeStrategyLadderDTO();
                    ladderDTO.setId(String.valueOf(ladderModel.getId()));
                    ladderDTO.setTimeStrategyId(String.valueOf(ladderModel.getTimeStrategyId()));
                    ladderDTO.setLadderTime(ladderModel.getLadderTime());
                    ladderDTO.setSectionDown(ladderModel.getSectionDown());
                    ladderDTO.setSectionUp(ladderModel.getSectionUp());
                    ladderDTO.setSectionDownSymbol(ladderModel.getSectionDownSymbol());
                    ladderDTO.setSectionUpSymbol(ladderModel.getSectionUpSymbol());
                    ladderDTO.setSectionDownSymbolName(ConvertorUtil.getName(dicData, BmsConstant.SECTION_SYMBOL, String.valueOf(ladderModel.getSectionDownSymbol())));
                    ladderDTO.setSectionUpSymbolName(ConvertorUtil.getName(dicData, BmsConstant.LESS_THAN, String.valueOf(ladderModel.getSectionUpSymbol())));
                    ladderDTOS.add(ladderDTO);
                }
                strategyDTO.setTimeStrategyLadderDTOS(ladderDTOS);
            }
        }
        return strategyDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(BmsTimeStrategyVO vo) {
        if (ObjectUtil.isEmpty(vo.getId())) {
            throw new PluginException("修改参数不能为空");
        }
        BmsTimeBillStrategyModel model = mapper.findById(vo.getId(), BmsTimeBillStrategyModel.class);
        if (ObjectUtil.isEmpty(model)) {
            throw new PluginException("查询时间策略数据不存在");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        BeanUtils.copyProperties(vo, model);
        model.setUpdateperson(user.getNickname());
        model.setUpdatetime(DateUtil.date());
        model.setTimeInteger(vo.getTimeInteger());
        model.setTimePrecision(vo.getTimePrecision());
        model.setTimeLadderEnable(vo.getTimeLadderEnable());
        mapper.update(model);

        // 修改时间策略阶梯
        if (vo.getTimeLadderEnable().intValue() == 0) {
            Criteria criteria = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
            Restriction r1 = Restrictions.eq(BmsTimeBillStrategyLadderModel::getTimeStrategyId, model.getId());
            Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            ladderMapper.deleteByCriteria(criteria);
        } else {
            if (ObjectUtil.isNotEmpty(vo.getTimeStrategyLadderVOS())) {
                long size  = vo.getTimeStrategyLadderVOS().stream().filter(time->ObjectUtil.isEmpty(time.getLadderTime()) || NumberUtil.isLessOrEqual(time.getLadderTime(), BigDecimal.ZERO)).collect(Collectors.toList()).size();
                if (size > 0) {
                    throw new PrologException("计费时间不为空");
                }
                List<Long> ids = vo.getTimeStrategyLadderVOS().stream().filter(time->ObjectUtil.isNotEmpty(time.getId())).map(time->Long.valueOf(time.getId())).collect(Collectors.toList());
                if (ObjectUtil.isNotEmpty(ids)) {
                    Criteria criteria = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
                    Restriction r1 = Restrictions.eq(BmsTimeBillStrategyLadderModel::getTimeStrategyId, model.getId());
                    Restriction r2 = Restrictions.notIn(BmsTimeBillStrategyLadderModel::getId, ids.stream().toArray());
                    criteria.setRestriction(Restrictions.and(r1, r2));
                    ladderMapper.deleteByCriteria(criteria);
                } else {
                    Criteria criteria = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
                    Restriction r1 = Restrictions.eq(BmsTimeBillStrategyLadderModel::getTimeStrategyId, model.getId());
                    Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
                    criteria.setRestriction(Restrictions.and(r1, r2));
                    ladderMapper.deleteByCriteria(criteria);
                }

                for (BmsTimeStrategyLadderVO ladderVO : vo.getTimeStrategyLadderVOS()) {
                    if (ObjectUtil.isNotEmpty(ladderVO.getId())) {
                        Map<String, Object> ladderMap = new HashMap<>();
                        ladderMap.put("updateperson", user.getNickname());
                        ladderMap.put("updatetime", DateUtil.date());
                        ladderMap.put("ladderTime", ladderVO.getLadderTime());
                        ladderMap.put("sectionUp", ladderVO.getSectionUp());
                        ladderMap.put("sectionDownSymbol", ladderVO.getSectionUpSymbol());
                        ladderMap.put("sectionDown", ladderVO.getSectionDown());
                        ladderMap.put("sectionDownSymbol", ladderVO.getSectionDownSymbol());
                        ladderMapper.updateMapById(Long.valueOf(ladderVO.getId()), ladderMap, BmsTimeBillStrategyLadderModel.class);
                    } else {
                        BmsTimeBillStrategyLadderModel ladderModel = new BmsTimeBillStrategyLadderModel();
                        ladderModel.setId(null);
                        ladderModel.setTimeStrategyId(Long.valueOf(vo.getId()));
                        ladderModel.setSectionUp(ladderVO.getSectionUp());
                        ladderModel.setSectionUpSymbol(ladderVO.getSectionUpSymbol());
                        ladderModel.setSectionDown(ladderVO.getSectionDown());
                        ladderModel.setSectionDownSymbol(ladderVO.getSectionDownSymbol());
                        ladderModel.setLadderTime(ladderVO.getLadderTime());
                        ladderModel.setCreateperson(user.getNickname());
                        ladderModel.setCreatetime(DateUtil.date());
                        ladderModel.setUpdateperson(user.getNickname());
                        ladderModel.setUpdatetime(DateUtil.date());
                        ladderModel.setEnterpriseId(user.getEnterpriseId());
                        ladderModel.setEnterpriseName(user.getEnterpriseName());
                        ladderMapper.save(ladderModel);
                    }
                }
            }
        }
    }

    @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) {
            BmsTimeBillStrategyModel model = mapper.findById(statusUpdate.getId(), BmsTimeBillStrategyModel.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) {
            BmsTimeBillStrategyModel model = mapper.findById(id, BmsTimeBillStrategyModel.class);
            if (model.getStatus() == 1) {
                throw new PluginException(String.format("时间策略[%s],是启用状态不能删除", model.getStrategyName()));
            }
            mapper.deleteById(id, BmsTimeBillStrategyModel.class);

            Criteria criteria = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
            Restriction r1 = Restrictions.eq(BmsTimeBillStrategyLadderModel::getTimeStrategyId, id);
            criteria.setRestriction(Restrictions.and(r1));
            ladderMapper.deleteByCriteria(criteria);
        }
    }
}