package com.fjhx.service.water.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.Condition;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.water.WaterDetail;
import com.fjhx.entity.water.WaterTag;
import com.fjhx.enums.InTypeEnum;
import com.fjhx.enums.MaterialTypeEnum;
import com.fjhx.enums.OutTypeEnum;
import com.fjhx.mapper.water.WaterDetailMapper;
import com.fjhx.params.water.WaterVo;
import com.fjhx.service.water.WaterDetailService;
import com.fjhx.utils.UserClientUtil;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 流水明细表 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-09-16
 */
@Service
public class WaterDetailServiceImpl extends ServiceImpl<WaterDetailMapper, WaterDetail> implements WaterDetailService {

    @Override
    public void add(WaterVo waterVo, List<WaterTag> waterTagList) {

        // 添加标签明细
        List<WaterDetail> waterDetailList = new ArrayList<>();
        for (WaterTag waterTag : waterTagList) {
            WaterDetail waterDetail = new WaterDetail();
            waterDetail.setWaterId(waterVo.getId());
            waterDetail.setWaterBatchId(waterTag.getWaterBatchId());
            waterDetail.setWaterTagId(waterTag.getId());
            waterDetail.setOperUserId(waterVo.getOperUserId());
            waterDetail.setMaterialId(waterTag.getMaterialId());
            waterDetail.setQuantity(waterTag.getQuantity());
            waterDetail.setQrCode(waterTag.getQrCode());
            waterDetail.setRfidCode(waterTag.getRfidCode());
            waterDetail.setPrice(waterTag.getPrice());
            waterDetail.setType(waterVo.getType());
            waterDetail.setDevice(waterVo.getDevice());
            waterDetailList.add(waterDetail);
        }

        saveBatch(waterDetailList);
    }

    @Override
    public List<Map<String, Object>> getInQuantityByApplyPurchaseDetailsId(Condition condition) {
        Long applyPurchaseDetailsId = condition.getLong("applyPurchaseDetailsId");
        List<Map<String, Object>> list = baseMapper.getInQuantityByApplyPurchaseDetailsId(applyPurchaseDetailsId);

        // 赋值用户名称
        UserClientUtil.setUserName(list, "operUserId", "operUserName");

        return list;
    }

    @Override
    public Map<String, Object> pickingStatistics(Condition condition) {

        QueryWrapper<Object> wrapper = getPickingWrapper(condition);

        List<Map<String, Object>> pickingList = baseMapper.getPickingList(wrapper);
        if (pickingList.size() > 0) {
            // 赋值用户名称
            UserClientUtil.setUserName(pickingList, "userId", "userName");
        }

        HashMap<String, Object> result = new HashMap<>();

        // 按物料属性分组
        Map<String, List<Map<String, Object>>> groupByStatistics = pickingList.stream().collect(
                Collectors.groupingBy(item -> item.get("materialType").toString()));

        // 统计面料
        HashMap<String, Object> fabricStatistics = new HashMap<>();
        fabricStatistics.put("total", 0);
        fabricStatistics.put("length", BigDecimal.ZERO);
        fabricStatistics.put("measureArea", BigDecimal.ZERO);
        fabricStatistics.put("money", BigDecimal.ZERO);

        // 面料属性属性
        List<Map<String, Object>> fabricTree = new ArrayList<>();

        // 构建前端所需参数
        for (Map.Entry<String, List<Map<String, Object>>> entry : groupByStatistics.entrySet()) {
            String key = entry.getKey();
            List<Map<String, Object>> value = entry.getValue();

            // 墨水统计
            if (key.equals("3")) {
                // 墨水统计
                HashMap<Object, Object> inkStatistics = new HashMap<>();
                // 件数
                inkStatistics.put("total", value.size());
                // 公斤
                inkStatistics.put("weight", value.stream().map(item -> (BigDecimal) item.get("changeNum"))
                        .reduce(BigDecimal.ZERO, BigDecimal::add));
                // 金额
                inkStatistics.put("money", value.stream()
                        .map(item -> ((BigDecimal) item.get("changeNum")).multiply((BigDecimal) item.get("materialPrice")))
                        .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP));

                result.put("inkStatistics", inkStatistics);

                // 墨水领料明细
                List<HashMap<String, Object>> inkDetails = new ArrayList<>(value.stream().collect(Collectors.toMap(
                        item -> item.get("userId").toString(), // 根据用户id分组
                        item -> { // 统计单条数据
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("userId", item.get("userId"));
                            map.put("userName", item.get("userName"));
                            map.put("total", 1);
                            map.put("weight", item.get("changeNum"));
                            map.put("money", ((BigDecimal) item.get("changeNum"))
                                    .multiply((BigDecimal) item.get("materialPrice")).setScale(2, RoundingMode.HALF_UP));
                            return map;
                        },
                        (v1, v2) -> { // 当有多条用户记录时，统计数据
                            v1.put("total", ((Integer) v1.get("total")) + 1);
                            v1.put("weight", ((BigDecimal) v1.get("weight")).add((BigDecimal) v2.get("weight")));
                            v1.put("money", ((BigDecimal) v1.get("money")).add((BigDecimal) v2.get("money")));
                            return v1;
                        })).values());

                result.put("inkDetails", inkDetails);
            }
            // 面料统计
            else {
                // 卷数
                int size = value.size();
                // 米数
                BigDecimal length = value.stream().map(item -> (BigDecimal) item.get("changeNum")).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 面积
                BigDecimal measureArea = value.stream().map(item -> ((BigDecimal) item.get("changeNum"))
                                .multiply(BigDecimal.valueOf((float) item.get("materialWidth")))
                                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP))
                        .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);
                // 金额
                BigDecimal money = value.stream().map(item -> ((BigDecimal) item.get("changeNum")).multiply((BigDecimal) item.get("materialPrice")))
                        .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);

                // 添加到面料统计
                fabricStatistics.put("total", (Integer) fabricStatistics.get("total") + size);
                fabricStatistics.put("length", ((BigDecimal) fabricStatistics.get("length")).add(length));
                fabricStatistics.put("measureArea", ((BigDecimal) fabricStatistics.get("measureArea")).add(measureArea));
                fabricStatistics.put("money", ((BigDecimal) fabricStatistics.get("money")).add(money));

                // 构建树形
                Map<String, Object> attribute = new HashMap<>();
                attribute.put("materialType", key);
                attribute.put("total", size);
                attribute.put("length", length);
                attribute.put("measureArea", measureArea);
                attribute.put("money", money);
                attribute.put("name", MaterialTypeEnum.getName(Convert.toInt(key)));

                // 查询子集
                List<HashMap<String, Object>> children = new ArrayList<>(value.stream().collect(Collectors.toMap(
                        item -> item.get("userId").toString(), // 根据用户id分组
                        item -> { // 统计单条数据
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("userId", item.get("userId"));
                            map.put("name", item.get("userName"));
                            map.put("total", 1); // 数量
                            map.put("length", item.get("changeNum")); // 米数

                            // 面积
                            map.put("measureArea", ((BigDecimal) item.get("changeNum"))
                                    .multiply(BigDecimal.valueOf((float) item.get("materialWidth")))
                                    .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)); // 面积
                            // 金额
                            map.put("money", ((BigDecimal) item.get("changeNum")).multiply((BigDecimal) item.get("materialPrice"))
                                    .setScale(2, RoundingMode.HALF_UP));
                            return map;
                        },
                        (v1, v2) -> { // 当有多条用户记录时，统计数据
                            v1.put("total", ((Integer) v1.get("total")) + 1);
                            v1.put("length", ((BigDecimal) v1.get("length")).add((BigDecimal) v2.get("length")));
                            v1.put("measureArea", ((BigDecimal) v1.get("measureArea")).add((BigDecimal) v2.get("measureArea")));
                            v1.put("money", ((BigDecimal) v1.get("money")).add((BigDecimal) v2.get("money")));
                            return v1;
                        })).values());

                attribute.put("children", children);

                fabricTree.add(attribute);
            }
        }

        // 面料统计
        result.put("fabricStatistics", fabricStatistics);

        // 面料树形
        result.put("fabricTree", fabricTree);

        return result;
    }

    @Override
    public Map<String, Integer> pickingTypeStatistics(Condition condition) {
        Integer materialType = condition.getInt("materialType");
        Long userId = condition.getLong("userId");

        QueryWrapper<Object> wrapper = getPickingWrapper(condition);
        wrapper.eq(ObjectUtil.isNotEmpty(materialType), "m.technology_type", materialType);
        wrapper.eq(ObjectUtil.isNotEmpty(userId), "wd.oper_user_id", userId);

        return baseMapper.pickingTypeStatistics(wrapper);
    }

    @Override
    public Page<Map<String, Object>> pickingPage(Condition condition) {
        Integer materialType = condition.getInt("materialType");
        Long userId = condition.getLong("userId");
        Integer type = condition.getInt("type");

        QueryWrapper<Object> wrapper = getPickingWrapper(condition);
        wrapper.eq(ObjectUtil.isNotEmpty(materialType), "m.technology_type", materialType);
        wrapper.eq(ObjectUtil.isNotEmpty(userId), "wd.oper_user_id", userId);
        wrapper.eq(ObjectUtil.isNotEmpty(type), "wd.type", type);

        Page<Map<String, Object>> page = baseMapper.pickingPage(condition.getPage(), wrapper);
        List<Map<String, Object>> records = page.getRecords();
        if (records.size() == 0) {
            return page;
        }

        // 赋值用户名称
        UserClientUtil.setUserName(records, "operUserId", "realName");

        return page;
    }

    @Override
    public List<Map<String, Object>> getPickingToday() {
        Long userId = AuthUtil.getUserId();
        Date date = new Date();
        Date beginTime = DateUtil.beginOfDay(date);
        Date endTime = DateUtil.endOfDay(date);

        QueryWrapper<Object> wrapper = Wrappers.query();
        wrapper.eq("wd.oper_user_id", userId);
        wrapper.eq("wd.del_flag", StatusConstant.NOT_DELETED);
        wrapper.between("wd.create_time", beginTime, endTime);

        return baseMapper.getPickingToday(wrapper);
    }

    private QueryWrapper<Object> getPickingWrapper(Condition condition) {
        Date beginTime = condition.getBeginTime();
        Date endTime = condition.getEndTime();

        QueryWrapper<Object> wrapper = Wrappers.query();
        wrapper.in("wd.type",
                        OutTypeEnum.ISSUE.getType(),
                        OutTypeEnum.REPLENISHMENT.getType(),
                        InTypeEnum.BACK.getType())
                .eq("wd.del_flag", StatusConstant.NOT_DELETED)
                .between(ObjectUtil.isAllNotEmpty(beginTime, endTime), "wd.create_time", beginTime, endTime);
        return wrapper;
    }

}
