package com.fjhx.apply.service.impl;

import cn.hutool.core.date.DateTime;
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.apply.mapper.ApplyPurchaseMapper;
import com.fjhx.apply.service.ApplyPurchaseService;
import com.fjhx.entity.apply.ApplyPurchase;
import com.fjhx.entity.stock.StockWater;
import com.fjhx.stock.service.StockWaterService;
import com.fjhx.utils.Assert;
import com.fjhx.utils.BigDecimalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 申购单 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-08-04
 */
@Service
public class ApplyPurchaseServiceImpl extends ServiceImpl<ApplyPurchaseMapper, ApplyPurchase> implements ApplyPurchaseService {

    @Autowired
    private StockWaterService stockWaterService;

    @Override
    public Map<String, Map<String, Object>> technologyTypeStatistics(Map<String, String> condition) {
        QueryWrapper<Object> wrapper = getApplyPurchaseTimeWrapper(condition);

        String keyword = condition.get("keyword");
        if (ObjectUtil.isNotEmpty(keyword)) {
            wrapper.and(q -> q.like("m.Code", keyword).or().like("m.Name", keyword));
        }
        wrapper.groupBy("apd.ID");

        List<Map<String, Object>> list = baseMapper.technologyTypeStatistics(wrapper);

        Map<String, Map<String, Object>> technologyType = list.stream().collect(Collectors.toMap(
                item -> item.get("technologyType").toString(),
                item -> {
                    // 数量
                    item.put("purchaseQty", BigDecimalUtil.keepDecimals(item.get("purchaseQty"), 1));

                    if (!item.get("technologyType").toString().equals("3")) {
                        // 赋值面积
                        item.put("area", BigDecimalUtil.init(item.get("purchaseQty")).multiply(item.get("width")).divide(100, 1).getValue());
                    }

                    item.remove("width");
                    return item;
                },
                (v1, v2) -> {
                    if (!v1.get("technologyType").toString().equals("3")) {
                        v1.put("area", BigDecimalUtil.add(v1.get("area"), v2.get("area")));
                    }
                    v1.put("purchaseQty", BigDecimalUtil.add(v1.get("purchaseQty"), v2.get("purchaseQty")));
                    v1.put("num", BigDecimalUtil.add(v1.get("num"), v2.get("num")));
                    return v1;
                }
        ));

        Map<String, Object> initMap = new HashMap<>();

        initMap.put("area", BigDecimal.ZERO);
        initMap.put("purchaseQty", BigDecimal.ZERO);
        initMap.put("num", BigDecimal.ZERO);

        Map<String, Object> initMap0 = ObjectUtil.clone(initMap);
        initMap0.put("technologyType", 0);
        technologyType.putIfAbsent("0", initMap0);

        Map<String, Object> initMap1 = ObjectUtil.clone(initMap);
        initMap1.put("technologyType", 1);
        technologyType.putIfAbsent("1", initMap1);

        Map<String, Object> initMap2 = ObjectUtil.clone(initMap);
        initMap2.put("technologyType", 2);
        technologyType.putIfAbsent("2", initMap2);

        Map<String, Object> initMap3 = ObjectUtil.clone(initMap);
        initMap3.put("technologyType", 3);
        technologyType.putIfAbsent("3", initMap3);

        Map<String, Object> initMap4 = ObjectUtil.clone(initMap);
        initMap4.put("technologyType", 4);
        technologyType.putIfAbsent("4", initMap4);

        // 统计面料（0直喷，1热转，2打纸，4其他）之和
        HashMap<String, Object> fabricMap = new HashMap<>();

        Map<String, Object> technologyType0 = technologyType.get("0");
        Map<String, Object> technologyType1 = technologyType.get("1");
        Map<String, Object> technologyType2 = technologyType.get("2");
        Map<String, Object> technologyType4 = technologyType.get("4");

        fabricMap.put("area", BigDecimalUtil.init(technologyType0.get("area")).add(technologyType1.get("area"))
                .add(technologyType2.get("area")).add(technologyType4.get("area")).getValue());

        fabricMap.put("purchaseQty", BigDecimalUtil.init(technologyType0.get("purchaseQty")).add(technologyType1.get("purchaseQty"))
                .add(technologyType2.get("purchaseQty")).add(technologyType4.get("purchaseQty")).getValue());

        fabricMap.put("num", BigDecimalUtil.init(technologyType0.get("num")).add(technologyType1.get("num"))
                .add(technologyType2.get("num")).add(technologyType4.get("num")).getValue());

        fabricMap.put("technologyType", 5);

        technologyType.put("5", fabricMap);

        return technologyType;
    }

    @Override
    public List<Map<String, Object>> numStatistics(Map<String, String> condition) {

        String technologyType = condition.get("technologyType");

        QueryWrapper<Object> wrapper = getApplyPurchaseTimeWrapper(condition);

        String keyword = condition.get("keyword");
        if (ObjectUtil.isNotEmpty(keyword)) {
            wrapper.and(q -> q.like("m.Code", keyword).or().like("m.Name", keyword));
        }

        if (ObjectUtil.isNotEmpty(technologyType) && technologyType.equals("5")) {
            wrapper.in("m.TechnologyType", 0, 1, 2, 4);
        } else {
            wrapper.eq(ObjectUtil.isNotEmpty(technologyType), "m.TechnologyType", technologyType);
        }

        wrapper.groupBy("ap.ApproveBillState");

        List<Map<String, Object>> list = baseMapper.numStatistics(wrapper);

        Map<Integer, Long> collect = list.stream().collect(Collectors.toMap(
                item -> (Integer) item.get("approveBillState"),
                item -> (Long) item.get("count")
        ));

        Map<String, Object> approvedMap = new HashMap<>();
        approvedMap.put("key", "审批中");
        approvedMap.put("value", 1);
        approvedMap.put("count", (collect.get(0) == null ? 0 : collect.get(0)) + (collect.get(1) == null ? 0 : collect.get(1)));

        Map<String, Object> passedMap = new HashMap<>();
        passedMap.put("key", "已通过");
        passedMap.put("value", 2);
        passedMap.put("count", collect.get(2) == null ? 0 : collect.get(2));

        Map<String, Object> rejectedMap = new HashMap<>();
        rejectedMap.put("key", "已驳回");
        rejectedMap.put("value", 3);
        rejectedMap.put("count", collect.get(3) == null ? 0 : collect.get(3));

        Map<String, Object> wholeMap = new HashMap<>();
        wholeMap.put("key", "全部");
        wholeMap.put("count", (Long) approvedMap.get("count") + (Long) passedMap.get("count") + (Long) rejectedMap.get("count"));

        return Arrays.asList(wholeMap, approvedMap, rejectedMap, passedMap);
    }

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

        String technologyType = condition.get("technologyType");

        String status = condition.get("status");

        QueryWrapper<Object> wrapper = getApplyPurchaseTimeWrapper(condition);

        String keyword = condition.get("keyword");
        if (ObjectUtil.isNotEmpty(keyword)) {
            wrapper.and(q -> q.like("m.Code", keyword).or().like("m.Name", keyword));
        }

        if (ObjectUtil.isNotEmpty(technologyType) && technologyType.equals("5")) {
            wrapper.in("m.TechnologyType", 0, 1, 2, 4);
        } else {
            wrapper.eq(ObjectUtil.isNotEmpty(technologyType), "m.TechnologyType", technologyType);
        }

        if (ObjectUtil.isNotEmpty(status)) {
            if (Objects.equals(status, "1")) {
                wrapper.in("ap.ApproveBillState", 0, 1);
            } else {
                wrapper.eq("ap.ApproveBillState", status);
            }
        }
        wrapper.groupBy("apd.ID");

        Map<String, Object> map = baseMapper.totalNumStatistics(wrapper);
        if (map == null) {
            map = new HashMap<>();
            map.put("purchaseQuantity", 0);
            map.put("onTheWayQuantity", 0);
        } else {
            map.put("purchaseQuantity", BigDecimalUtil.keepDecimals(map.get("purchaseQuantity"), 1));
            map.put("onTheWayQuantity", BigDecimalUtil.keepDecimals(map.get("onTheWayQuantity"), 1));
        }
        return map;
    }

    @Override
    public Page<Map<String, Object>> getPage(Map<String, String> condition) {
        String keyword = condition.get("keyword");
        String technologyType = condition.get("technologyType");
        String status = condition.get("status");
        QueryWrapper<Object> wrapper = getApplyPurchaseTimeWrapper(condition);

        if (ObjectUtil.isNotEmpty(keyword)) {
            wrapper.and(q -> q.like("m.Code", keyword).or().like("m.Name", keyword));
        }
        if (ObjectUtil.isNotEmpty(technologyType) && technologyType.equals("5")) {
            wrapper.in("m.TechnologyType", 0, 1, 2, 4);
        } else {
            wrapper.eq(ObjectUtil.isNotEmpty(technologyType), "m.TechnologyType", technologyType);
        }

        wrapper.eq(ObjectUtil.isNotEmpty(status), "ap.ApproveBillState", status);
        wrapper.orderByAsc("pc.PurContractState");
        wrapper.orderByDesc("ap.CreatedTime");

        Page<Map<String, Object>> page = baseMapper.getPage(createPage(condition), wrapper);

        List<Map<String, Object>> records = page.getRecords();
        if (records.size() == 0) {
            return page;
        }

        // 获取物料编码集合
        List<String> materialCodeList = records.stream()
                .map(item -> item.get("materialCode").toString()).collect(Collectors.toList());

        // 查询库存，最长滞留时间和滞留超过30天数量
        Date date = new Date();
        DateTime dateTime = DateUtil.offsetDay(date, -30);
        Map<String, Map<String, Object>> delayMap = baseMapper.selectDelay(
                dateTime,
                Wrappers.query().in("sd.MaterialCode", materialCodeList).groupBy("sd.MaterialCode")
        );

        // 近30天消耗量
        Map<String, Object> consumeMap = stockWaterService.listMaps(
                Wrappers.<StockWater>query().select("sum(TotalQty) overUseQty", "MaterialCode materialCode")
                        .lambda()
                        .in(StockWater::getStockchangetype, 20, 23)
                        .gt(StockWater::getCreatedtime, dateTime)
                        .groupBy(StockWater::getMaterialcode)
        ).stream().collect(Collectors.toMap(
                item -> item.get("materialCode").toString(),
                item -> item.get("overUseQty")
        ));

        for (Map<String, Object> record : records) {
            String materialCode = record.get("materialCode").toString();
            Map<String, Object> map = delayMap.get(materialCode);

            if (map != null) {
                record.putAll(map);
                record.put("maxDelayTime", DateUtil.betweenDay(date, (Date) map.get("maxDelayTime"), true));
            }

            record.putIfAbsent("stockQty", 0);
            record.putIfAbsent("maxDelayTime", 0);
            record.putIfAbsent("delayQuantity", 0);

            Object overUseQty = consumeMap.get(materialCode);
            record.put("overUseQty", overUseQty == null ? BigDecimal.ZERO : overUseQty);

            record.put("purchaseQty", BigDecimalUtil.keepDecimals(record.get("purchaseQty")));
            record.put("onWayQuantity", BigDecimalUtil.keepDecimals(record.get("onWayQuantity")));

            int purContractState = Integer.parseInt(record.get("purContractState").toString());
            switch (purContractState) {
                case 0:
                    record.put("purContractState", "待确认");
                    break;
                case 1:
                    record.put("purContractState", "审批中");
                    break;
                case 2:
                    record.put("purContractState", "进行中");
                    break;
                case 3:
                    record.put("purContractState", "已完成");
            }
        }

        return page;
    }

    /**
     * 领料追踪统计获取wrapper
     */
    private QueryWrapper<Object> getApplyPurchaseTimeWrapper(Map<String, String> condition) {
        String type = condition.get("type");
        Assert.notEmpty(type, "时间类型不能为空");
        Date beginTime;
        Date endTime;
        Date date = new Date();
        switch (type) {
            case "1":
                beginTime = DateUtil.beginOfDay(date);
                endTime = DateUtil.endOfDay(date);
                break;
            case "2":
                beginTime = DateUtil.beginOfWeek(date);
                endTime = DateUtil.endOfWeek(date);
                break;
            case "3":
                beginTime = DateUtil.beginOfMonth(date);
                endTime = DateUtil.endOfMonth(date);
                break;
            case "4":
                beginTime = DateUtil.beginOfYear(date);
                endTime = DateUtil.endOfYear(date);
                break;
            default:
                beginTime = DateUtil.beginOfDay(DateUtil.parse(condition.get("beginTime")));
                endTime = DateUtil.endOfDay(DateUtil.parse(condition.get("endTime")));
        }

        return Wrappers.query().between("ap.CreatedTime", beginTime, endTime);
    }

}
