package com.dsk.cscec.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dsk.common.constant.GlobalConstants;
import com.dsk.common.core.domain.R;
import com.dsk.common.exception.ServiceException;
import com.dsk.common.helper.LoginHelper;
import com.dsk.common.utils.redis.RedisUtils;
import com.dsk.cscec.domain.CbQuantitySummary;
import com.dsk.cscec.domain.CbQuantitySummaryActual;
import com.dsk.cscec.domain.CbSubject;
import com.dsk.cscec.domain.bo.CbProjectBaseBo;
import com.dsk.cscec.domain.bo.CbQuantitySummaryListBo;
import com.dsk.cscec.domain.vo.CbQuantitySummaryListVo;
import com.dsk.cscec.mapper.CbQuantitySummaryMapper;
import com.dsk.cscec.mapper.CbSubjectMapper;
import com.dsk.cscec.service.ICbQuantitySummaryActualService;
import com.dsk.cscec.service.ICbQuantitySummaryService;
import jodd.bean.BeanException;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 成本-工料汇总基本表(CbQuantitySummary)表服务实现类
 *
 * @author lcl
 * @since 2024-02-05 11:06:56
 */
@Slf4j
@Service
public class CbQuantitySummaryServiceImpl extends ServiceImpl<CbQuantitySummaryMapper, CbQuantitySummary> implements ICbQuantitySummaryService {

    @Autowired
    private ICbQuantitySummaryActualService baseActualService;
    @Resource
    private CbSubjectMapper cbSubjectMapper;

    @Override
    public List<Map<String, Object>> subjectTree(CbProjectBaseBo bo) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        List<Map<String, Object>> list = baseMapper.selectSubject(bo);
        if (!ObjectUtils.isEmpty(list)) {
            Map<String, Map<String, Map<String, Map<String, List<Map<String, Object>>>>>> map = list.stream()
                    .collect(
                            Collectors.groupingBy(item -> item.get("one").toString(),
                                    Collectors.groupingBy(item -> item.get("two").toString(),
                                            Collectors.groupingBy(item -> item.get("three").toString(),
                                                    Collectors.groupingBy(item -> item.get("four").toString()
                                                    )))));
            Map<String, Object> resMap = new HashMap<>();
            List<Map<String, Object>> resList = new ArrayList<>();
            resMap.put("name", "房建类成本科目");
            resMap.put("sort", 1);
            for (Map.Entry<String, Map<String, Map<String, Map<String, List<Map<String, Object>>>>>> entry : map.entrySet()) {
                Map<String, Object> oneMap = new HashMap<>();
                List<Map<String, Object>> oneList = new ArrayList<>();
                oneMap.put("name", entry.getKey());
                oneMap.put("sort", cbSubjectMapper.selectOne(Wrappers.<CbSubject>lambdaQuery().eq(CbSubject::getCbSubjectName, entry.getKey())).getSort());
                for (Map.Entry<String, Map<String, Map<String, List<Map<String, Object>>>>> twoEntry : entry.getValue().entrySet()) {
                    Map<String, Object> twoMap = new HashMap<>();
                    List<Map<String, Object>> twoList = new ArrayList<>();
                    twoMap.put("name", twoEntry.getKey());
                    for (Map.Entry<String, Map<String, List<Map<String, Object>>>> threeEntry : twoEntry.getValue().entrySet()) {
                        Map<String, Object> threeMap = new HashMap<>();
                        List<Map<String, Object>> threeList = new ArrayList<>();
                        threeMap.put("name", threeEntry.getKey());
                        for (Map.Entry<String, List<Map<String, Object>>> fourEntry : threeEntry.getValue().entrySet()) {
                            Map<String, Object> fourMap = new HashMap<>();
                            fourMap.put("name", fourEntry.getKey());
                            threeList.add(fourMap);
                        }
                        threeMap.put("children", threeList);
                        twoList.add(threeMap);
                    }
                    twoMap.put("children", twoList);
                    oneList.add(twoMap);
                }
                oneMap.put("children", oneList);
                resList.add(oneMap);
            }
            resMap.put("children", resList);
            resultList.add(resMap);
        }

        int otherSubjectCount = baseMapper.selectOtherSubjectCount(bo);
        if (otherSubjectCount > 0) {
            Map<String, Object> resMap = new HashMap<>();
            resMap.put("name", "未归类项目");
            resMap.put("sort", 2);
            resultList.add(resMap);
        }
        return resultList;
    }

    @Override
    public List<String> monthList(CbQuantitySummaryListBo bo) {
        return baseMapper.selectMonthList(bo);
    }

    @Override
    public List<CbQuantitySummaryListVo> subjectList(CbQuantitySummaryListBo bo) {
        if (ObjectUtils.isEmpty(bo.getRecordDate())) {
            //默认当前月
            bo.setRecordDate(DatePattern.SIMPLE_MONTH_FORMAT.format(new Date()));
        }
        if (ObjectUtils.isEmpty(bo.getProjectId())) throw new BeanException("项目id不能为空！");
        if (ObjectUtils.isEmpty(bo.getCbStage())) throw new BeanException("成本阶段不能为空！");
        List<CbQuantitySummaryListVo> listVo = baseMapper.selectListBySubject(bo);
        //超出计划成本合价(不含税)的集合
        List<CbQuantitySummaryListVo> outList = new ArrayList<>();
        //未超出计划成本合价(不含税)的集合
        List<CbQuantitySummaryListVo> notOutList = new ArrayList<>();
        listVo.forEach(vo -> {
            if (ObjectUtil.isNotNull(vo.getPushQuantities())) {
                //实际成本合价(不含税)
                vo.setActualCombinedPrice(vo.getQuantity() * vo.getPushQuantities());
            } else {
                //实际成本合价(不含税)
                vo.setActualCombinedPrice(
                        (ObjectUtil.isNull(vo.getPurchaseUnitPrice()) ? 0.0 : vo.getPurchaseUnitPrice())
                                *
                                (ObjectUtil.isNull(vo.getPushQuantities()) ? 0.0 : vo.getPushQuantities())
                );
            }

            //如果实际成本合价(不含税)超出了计划成本合价(不含税),则设置标识,以便前端标红
            Double combinedPrice = ObjectUtil.isNull(vo.getCombinedPrice()) ? 0.0 : vo.getCombinedPrice();
            if (vo.getActualCombinedPrice().compareTo(combinedPrice) > 0) {
                //vo.setActualCombinedPrice(Double.parseDouble(StringUtils.markInRed(vo.getActualCombinedPrice().toString(), vo.getActualCombinedPrice().toString())));
                vo.setIsActualGreaterThanPlan(true);
                outList.add(vo);
            } else {
                vo.setIsActualGreaterThanPlan(false);
                notOutList.add(vo);
            }
        });

        //筛选是否超出计划成本合价(不含税)
        Boolean flag = bo.getIsOutPlanCostCombinedPrice();
        if (ObjectUtil.isNotNull(flag)) {
            if (flag) {
                return outList;
            } else {
                return notOutList;
            }
        }
        return listVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateActual(List<CbQuantitySummaryActual> list) {
        if (ObjectUtils.isEmpty(list)) throw new BeanException("数据不能为空");
        String nickName = LoginHelper.getLoginUser().getNickname();
        for (CbQuantitySummaryActual actual : list) {
            if (ObjectUtils.isEmpty(actual.getCbQuantitySummaryId())) throw new BeanException("基础数据id不能为空！");
            if (ObjectUtils.isEmpty(actual.getQuantities())) throw new BeanException("工程量（本月用料）不能为空！");
            if (ObjectUtils.isEmpty(actual.getRecordDate())) throw new BeanException("填写月份不能为空！");
            actual.setId(ObjectUtils.isEmpty(actual.getId()) ? SecureUtil.md5(actual.getCbQuantitySummaryId() + actual.getRecordDate()) : actual.getId());
            actual.setUpdateBy(nickName);
            boolean b = baseActualService.saveOrUpdate(actual);
            if (!b) {
                log.error("CbQuantitySummaryServiceImpl.updateActual() data insert error! data:" + JSONUtil.toJsonStr(actual));
                throw new ServiceException("数据添加错误！");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pushData(CbQuantitySummaryActual bo) {
        //数据记录
        if (ObjectUtils.isEmpty(bo.getId())) throw new BeanException("id不能为空！");
        if (ObjectUtils.isEmpty(bo.getPushQuantities())) throw new BeanException("推送工程量不能为空！");
        if (ObjectUtils.isEmpty(bo.getIpmProjectCode())) throw new BeanException("IPM项目编码不能为空！");
        if (ObjectUtils.isEmpty(bo.getIpmContractCode())) throw new BeanException("IPM合同编码不能为空！");
        if (ObjectUtils.isEmpty(bo.getIpmBizCode())) throw new BeanException("IPM作业编码不能为空！");
        boolean update = baseActualService.updateById(bo);
        if (!update) {
            log.error("CbQuantitySummaryServiceImpl.pushData() data update error! data:" + JSONUtil.toJsonStr(bo));
            throw new ServiceException("数据添加错误！");
        }
        //TODO 推送数据

    }

    @Override
    public boolean batchInsert(List<CbQuantitySummary> list) {
        int i = baseMapper.batchInsert(list);
        return i == list.size();
    }

    @Override
    public R conversionNotice(CbQuantitySummaryListBo bo) {
        if (StringUtil.isBlank(bo.getRecordDate())) {
            //默认当前月
            bo.setRecordDate(DatePattern.SIMPLE_MONTH_FORMAT.format(new Date()));
        }
        //是否是实体工程材料
        CbSubject cbSubject = cbSubjectMapper.selectOne(new LambdaQueryWrapper<CbSubject>().eq(CbSubject::getCbSubjectName, bo.getCbSubjectName()));
        if (ObjectUtil.isNull(cbSubject)) {
            return R.ok();
        }
        if (cbSubject.getCbSubjectNo().startsWith("FG") || cbSubject.getCbSubjectNo().startsWith("JD")) {
            //是否存在未换算数据
            List<CbQuantitySummaryListVo> unconvertedList = baseMapper.unconvertedList(bo);
            if (CollectionUtil.isEmpty(unconvertedList)) {
                return R.ok();
            }
            //是否提示
            String key = GlobalConstants.UNIT_CONVERSION_NOTICE + LoginHelper.getUserId() + "_" + bo.getProjectId() + "_" + bo.getCbSubjectName() + "_" + bo.getRecordDate();
            if (ObjectUtil.isNull(RedisUtils.getCacheObject(key))) {
                Date now = new Date();
                long expireTime = DateUtil.between(now, DateUtil.endOfDay(now), DateUnit.SECOND);
                RedisUtils.setCacheObject(key, "noticed", Duration.ofSeconds(expireTime));
                return R.ok("系统检测到您近期未进行物料单位换算，请立即进行换算。", unconvertedList);
            }

        }
        return R.ok();
    }

    /**
     * 修改工程量
     */
    @Override
    public Boolean editEngineeringQuantity(CbQuantitySummaryActual bo) {
        if (ObjectUtils.isEmpty(bo.getId())) throw new BeanException("id不能为空！");
        if (ObjectUtils.isEmpty(bo.getPushQuantities())) throw new BeanException("修改后的工程量不能为空！");
        boolean update = baseActualService.updateById(bo);
        if (!update) {
            log.error("CbQuantitySummaryServiceImpl.editEngineeringQuantity() data update error! data:" + JSONUtil.toJsonStr(bo));
            throw new ServiceException("数据更新错误！");
        }
        return update;
    }
}

