package com.fjhx.applet.service.impl;

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.applet.mapper.FabricStatisticsMapper;
import com.fjhx.applet.service.FabricStatisticsService;
import com.fjhx.base.BaseEntity;
import com.fjhx.utils.Assert;
import com.fjhx.utils.WrapperUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springframework.stereotype.Service;

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

@Service
public class FabricStatisticsServiceImpl extends ServiceImpl<FabricStatisticsMapper, BaseEntity> implements FabricStatisticsService {

    @Override
    public Map<String, Object> selectFabricDetails() {
        List<Map<String, Object>> maps = baseMapper.selectFabricDetails();
        Map<String, Object> detailsMap = new HashMap<>();
        if (maps.size() > 0) {
            //计算合计件数
            int total = maps.stream().mapToInt(map -> Integer.parseInt(map.get("count").toString())).sum();

            //计算合计数量
            BigDecimal amountQuantity = maps.stream().map(map -> new BigDecimal(map.get("quantity").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算合计金额
            BigDecimal amountTotal = maps.stream().map(map -> new BigDecimal(map.get("amount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
            detailsMap.put("total", total);
            detailsMap.put("amountQuantity", amountQuantity);
            detailsMap.put("amountTotal", amountTotal);
        } else {
            detailsMap.put("total", 0);
            detailsMap.put("amountQuantity", 0);
            detailsMap.put("amountTotal", 0);
        }
        detailsMap.put("details", maps);
        return detailsMap;
    }

    @Override
    public List<Map<String, Object>> selectFabricTypeDetails(Map<String, Object> condition) {
        QueryWrapper<Object> wrapper = Wrappers.query();
        wrapper.eq(ObjectUtil.isNotNull(condition.get("technologyType")), "m.TechnologyType", condition.get("technologyType"));
        //判断选则了那个仓库  1为1号仓库  2为2号仓库  0 查询全部仓库
        if (Integer.parseInt(condition.get("houseType").toString()) == 1) {
            wrapper.eq("sd.StockHouseId", "c185883dba22478cb593d33f6b66cc53");
        } else if (Integer.parseInt(condition.get("houseType").toString()) == 2) {
            wrapper.eq("sd.StockHouseId", "0b8f584250bb4b40b72d641ce4849d15");
        }
        wrapper.groupBy("m.Purpose");
        return baseMapper.selectFabricTypeDetails(wrapper);
    }

    @Override
    public Map<String, Object> selectFabricWDetails(Map<String, Object> condition) {
        QueryWrapper<Object> wrapper = getDateWrapper("swd.CreatedTime", condition);
        wrapper.ne("m.TechnologyType", 3);
        wrapper.in("swd.StockChangeType", 10, 13);
        wrapper.groupBy("sh.id");
        List<Map<String, Object>> maps = baseMapper.selectFabricWDetails(wrapper);

        Map<String, Object> detailsMap = new HashMap<>();
        if (maps.size() > 0) {
            //计算合计件数
            int total = maps.stream().mapToInt(map -> Integer.parseInt(map.get("count").toString())).sum();

            //计算合计数量
            BigDecimal amountQuantity = maps.stream().map(map -> new BigDecimal(map.get("changeNum").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算合计金额
            BigDecimal amountTotal = maps.stream().map(map -> new BigDecimal(map.get("amount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
            detailsMap.put("total", total);
            detailsMap.put("amountQuantity", amountQuantity);
            detailsMap.put("amountTotal", amountTotal);
        } else {
            detailsMap.put("total", 0);
            detailsMap.put("amountQuantity", 0);
            detailsMap.put("amountTotal", 0);
        }
        detailsMap.put("details", maps);
        return detailsMap;
    }

    @Override
    public List<Map<String, Object>> selectFabricWTypeDetails(Map<String, Object> condition) {
        QueryWrapper<Object> wrapper = getDateWrapper("swd.CreatedTime", condition);
        wrapper.in("swd.StockChangeType", 10, 13);
        wrapper.eq("m.TechnologyType", condition.get("technologyType"));
        //判断选则了那个仓库  1为1号仓库  2为2号仓库  0 查询全部仓库
        if (Integer.parseInt(condition.get("houseType").toString()) == 1) {
            wrapper.eq("sh.id", "c185883dba22478cb593d33f6b66cc53");
        } else if (Integer.parseInt(condition.get("houseType").toString()) == 2) {
            wrapper.eq("sh.id", "0b8f584250bb4b40b72d641ce4849d15");
        }
        wrapper.groupBy("m.Purpose");
        return baseMapper.selectFabricWTypeDetails(wrapper);
    }

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

        QueryWrapper<Object> inOutBillWrapper = getDateWrapper("tsi.deviation_time", condition);
        inOutBillWrapper.groupBy("tsi.job_no", "m.technologyType");
        inOutBillWrapper.orderByAsc("m.technologyType");
        List<Map<String, Object>> inOutBill = baseMapper.getInOutBill(inOutBillWrapper);

        QueryWrapper<Object> waterStatisticsWrapper = getDateWrapper("swd.CreatedTime", condition);
        waterStatisticsWrapper.in("swd.StockChangeType", 20, 23);
        waterStatisticsWrapper.in("m.TechnologyType", 0, 1, 2, 4);
        waterStatisticsWrapper.groupBy("JobNo", "technologyType");
        List<Map<String, Object>> waterStatistics = baseMapper.getWaterStatistics(waterStatisticsWrapper);

        QueryWrapper<Object> returnMaterialWrapper = getDateWrapper("swd.CreatedTime", condition);
        returnMaterialWrapper.eq("swd.StockChangeType", 15);
        returnMaterialWrapper.in("m.TechnologyType", 0, 1, 2, 4);
        returnMaterialWrapper.groupBy("JobNo", "technologyType");
        List<Map<String, Object>> returnMaterial = baseMapper.getReturnMaterial(returnMaterialWrapper);


        Map<String, Map<String, Object>> collect = waterStatistics.stream().collect(
                Collectors.toMap(item -> item.get("jobNo").toString() + item.get("technologyType").toString(), item -> item));

        Map<String, Map<String, Object>> collect1 = returnMaterial.stream().collect(
                Collectors.toMap(item -> item.get("jobNo").toString() + item.get("technologyType").toString(), item -> item));

        for (Map<String, Object> map : inOutBill) {
            String key = map.get("jobNo").toString() + map.get("technologyType").toString();

            if (collect.get(key) != null) {
                map.putAll(collect.get(key));
                map.put("area", BigDecimal.valueOf((Double) map.get("area")));
            } else {
                map.put("quantity", BigDecimal.ZERO);
                map.put("amount", BigDecimal.ZERO);
                map.put("area", BigDecimal.ZERO);
                map.put("pcs", 0);
            }

            if (collect1.get(key) != null) {
                map.putAll(collect1.get(key));
            } else {
                map.put("backQty", BigDecimal.ZERO);
            }

            BigDecimal subtract = ((BigDecimal) map.get("area")).subtract(((BigDecimal) map.get("backQty")));
            if (subtract.compareTo(BigDecimal.ZERO) == 0) {
                map.put("outputRatio", BigDecimal.ZERO);
            } else {
                map.put("outputRatio", (((BigDecimal) map.get("planArea"))
                        .divide(subtract, 5, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100"))));
            }
        }

        Map<Integer, List<Map<String, Object>>> technologyTypeMap =
                inOutBill.stream().collect(Collectors.groupingBy(item -> Integer.valueOf(item.get("technologyType").toString())));

        List<Map<String, Object>> result = new ArrayList<>();

        HashMap<String, Object> totalMap = new HashMap<>();
        totalMap.put("realName", "合计");
        totalMap.put("type", 1);
        totalMap.put("planArea", BigDecimal.ZERO);
        totalMap.put("quantity", BigDecimal.ZERO);
        totalMap.put("amount", BigDecimal.ZERO);
        totalMap.put("area", BigDecimal.ZERO);
        totalMap.put("backQty", BigDecimal.ZERO);
        totalMap.put("pcs", 0);


        for (Integer technologyType : Arrays.asList(0, 1, 2, 4)) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("realName", technologyType == 0 ? "直喷" : technologyType == 1 ? "热转" : technologyType == 2 ? "打纸" : "其他");
            map.put("type", 2);

            List<Map<String, Object>> list = technologyTypeMap.get(technologyType);
            if (list == null) break;

            BigDecimal planArea = list.stream().map(item -> (BigDecimal) item.get("planArea")).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal quantity = list.stream().map(item -> (BigDecimal) item.get("quantity")).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal amount = list.stream().map(item -> (BigDecimal) item.get("amount")).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal area = list.stream().map(item -> (BigDecimal) item.get("area")).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal backQty = list.stream().map(item -> (BigDecimal) item.get("backQty")).reduce(BigDecimal.ZERO, BigDecimal::add);
            int pcs = list.stream().mapToInt(item -> Integer.parseInt(item.get("pcs").toString())).sum();
            map.put("planArea", planArea);
            map.put("quantity", quantity);
            map.put("amount", amount);
            map.put("area", area);
            map.put("pcs", pcs);
            map.put("backQty", backQty);

            BigDecimal subtract = ((BigDecimal) map.get("area")).subtract(((BigDecimal) map.get("backQty")));
            if (subtract.compareTo(BigDecimal.ZERO) == 0) {
                map.put("outputRatio", BigDecimal.ZERO);
            } else {
                map.put("outputRatio", (((BigDecimal) map.get("planArea"))
                        .divide(subtract, 5, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100"))));
            }

            result.add(map);
            result.addAll(list);

            totalMap.put("planArea", ((BigDecimal) totalMap.get("planArea")).add(planArea));
            totalMap.put("quantity", ((BigDecimal) totalMap.get("quantity")).add(quantity));
            totalMap.put("amount", ((BigDecimal) totalMap.get("amount")).add(amount));
            totalMap.put("area", ((BigDecimal) totalMap.get("area")).add(area));
            totalMap.put("backQty", ((BigDecimal) totalMap.get("backQty")).add(backQty));
            totalMap.put("pcs", ((Integer) totalMap.get("pcs")) + pcs);
        }


        BigDecimal subtract = ((BigDecimal) totalMap.get("area")).subtract(((BigDecimal) totalMap.get("backQty")));
        if (subtract.compareTo(BigDecimal.ZERO) == 0) {
            totalMap.put("outputRatio", BigDecimal.ZERO);
        } else {
            totalMap.put("outputRatio", (((BigDecimal) totalMap.get("planArea"))
                    .divide(subtract, 5, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"))));
            result.add(0, totalMap);
        }

        return result;
    }

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

        Object type = condition.get("type");
        Assert.notEmpty(type, "类型参数不能为null");

        QueryWrapper<Object> wrapper = Wrappers.query();

        //1为1号仓库 2为2号仓库
        if (Integer.parseInt(type.toString()) == 1) {
            wrapper.eq("sd.StockHouseId", "c185883dba22478cb593d33f6b66cc53");
        } else if (Integer.parseInt(type.toString()) == 2) {
            wrapper.eq("sd.StockHouseId", "0b8f584250bb4b40b72d641ce4849d15");
        }

        wrapper.ne("m.TechnologyType", 3);
        wrapper.groupBy("m.TechnologyType");
        //查询明细
        List<Map<String, Object>> maps = baseMapper.selectFabricStatistics(wrapper);

        Map<String, Object> detailsMap = new HashMap<>();
        if (maps.size() > 0) {
            //计算合计件数
            int total = maps.stream().mapToInt(map -> Integer.parseInt(map.get("count").toString())).sum();

            //计算合计数量
            BigDecimal amountQuantity = maps.stream().map(map -> new BigDecimal(map.get("quantity").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算合计金额
            BigDecimal amountTotal = maps.stream().map(map -> new BigDecimal(map.get("amount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, BigDecimal.ROUND_HALF_UP);
            detailsMap.put("total", total);
            detailsMap.put("amountQuantity", amountQuantity);
            detailsMap.put("amountTotal", amountTotal);
        } else {
            detailsMap.put("total", 0);
            detailsMap.put("amountQuantity", 0);
            detailsMap.put("amountTotal", 0);
        }
        detailsMap.put("details", maps);
        return detailsMap;
    }

    @Override
    public Map<String, Object> selectFabricEW(Map<String, Object> condition) {
        QueryWrapper<Object> wrapper = getDateWrapper("swd.CreatedTime", condition);
        wrapper.in("swd.StockChangeType", 20, 23);
        wrapper.ne("m.TechnologyType", 3);
        wrapper.groupBy("m.TechnologyType");
        Map<String, String> pickingMap = selectPicking(condition);

        List<Map<String, Object>> maps = baseMapper.selectFabricEW(wrapper);

        for (Map<String, Object> map : maps) {
            String quantity = pickingMap.get(map.get("technologyType").toString());
            if (ObjectUtil.isNotEmpty(quantity)) {
                map.put("quantity", pickingMap.get(map.get("technologyType").toString()));
            } else {
                map.put("quantity", 0);
            }
        }

        Map<String, Object> detailsMap = new HashMap<>();
        if (maps.size() > 0 || ObjectUtil.isNotEmpty(maps)) {
            //计算合计件数
            int total = maps.stream().mapToInt(map -> Integer.parseInt(map.get("count").toString())).sum();

            //计算合计数量
            BigDecimal amountQuantity = maps.stream().map(map -> new BigDecimal(map.get("changeNum").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算合计金额
            BigDecimal amountTotal = maps.stream().map(map -> new BigDecimal(map.get("amount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算合计的排班面积
            BigDecimal quantity = maps.stream().map(map -> new BigDecimal(map.get("quantity").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算总的平方
            BigDecimal square = maps.stream().map(map -> new BigDecimal(map.get("square").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            detailsMap.put("total", total);
            detailsMap.put("amountQuantity", amountQuantity);
            detailsMap.put("amountTotal", amountTotal);
            detailsMap.put("quantity", quantity);
            detailsMap.put("square", square);
        } else {
            detailsMap.put("total", 0);
            detailsMap.put("amountQuantity", 0);
            detailsMap.put("amountTotal", 0);
            // detailsMap.put("quantity", 0);
            detailsMap.put("square", 0);
        }
        detailsMap.put("details", maps);
        return detailsMap;
    }

    @Override
    public Map<String, Object> selectFabricW(Map<String, Object> condition) {
        QueryWrapper<Object> wrapper = getDateWrapper("swd.CreatedTime", condition);
        //判断选则了那个仓库  1为1号仓库  2为2号仓库  0 查询全部仓库
        if (Integer.parseInt(condition.get("houseType").toString()) == 1) {
            wrapper.eq("sw.StockHouseId", "c185883dba22478cb593d33f6b66cc53");
        } else if (Integer.parseInt(condition.get("houseType").toString()) == 2) {
            wrapper.eq("sw.StockHouseId", "0b8f584250bb4b40b72d641ce4849d15");
        }
        wrapper.in("swd.StockChangeType", 10, 13);
        wrapper.ne("m.TechnologyType", 3);
        wrapper.groupBy("m.TechnologyType");
        List<Map<String, Object>> maps = baseMapper.selectFabricW(wrapper);
        Map<String, Object> detailsMap = new HashMap<>();
        if (maps.size() > 0) {
            //计算合计件数
            int total = maps.stream().mapToInt(map -> Integer.parseInt(map.get("count").toString())).sum();

            //计算合计数量
            BigDecimal amountQuantity = maps.stream().map(map -> new BigDecimal(map.get("totalQty").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);

            //计算合计金额
            BigDecimal amountTotal = maps.stream().map(map -> new BigDecimal(map.get("amount").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
            detailsMap.put("total", total);
            detailsMap.put("amountQuantity", amountQuantity);
            detailsMap.put("amountTotal", amountTotal);
        } else {
            detailsMap.put("total", 0);
            detailsMap.put("amountQuantity", 0);
            detailsMap.put("amountTotal", 0);
        }

        detailsMap.put("details", maps);
        return detailsMap;
    }

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

        WrapperUtil flowWrapper = getFlowWrapper(condition);

        QueryWrapper<?> wrapper = flowWrapper.getWrapper();
        if (ObjectUtil.isEmpty(condition.get("checkState"))) {
            wrapper.in("fa.CheckState", 0, 1, 2, 3);
        }

        wrapper.groupBy("f.ID");

        return baseMapper.flowNum(wrapper);
    }

    @Override
    public Page<Map<String, Object>> flowPage(Map<String, String> condition) {
        WrapperUtil flowWrapper = getFlowWrapper(condition);
        flowWrapper.eq("fa.ID", "id");
        flowWrapper.like("fa.ApprovalItem", "keyword");

        QueryWrapper<?> wrapper = flowWrapper.getWrapper();

        if (ObjectUtil.isEmpty(condition.get("checkState"))) {
            wrapper.in("fa.CheckState", 0, 1, 2, 3);
        }

        return baseMapper.flowPage(createPageMap(condition), wrapper);
    }

    @Override
    public Integer getApproveType(Map<String, String> condition) {
        String modelName = condition.get("modelName");
        String linkId = condition.get("linkId");

        if (!ObjectUtil.isAllNotEmpty(modelName, linkId)) {
            throw new ServiceException("modelName 或 linkId 不为空");
        }

        switch (modelName) {
            case "PurchaseContract":
                return null;
            case "PurchaseContractDel":
                modelName = "purchase_Contractdel";
                break;
            case "StockExemptCheck":
                modelName = "Stock_exemptcheck";
                break;
            case "SupplierShipApply":
                modelName = "supplier_shipapply";
                break;
            case "ApplyPurchasePay":
                modelName = "apply_purchase_pay";
                break;
            case "ApplyTake":
                modelName = "apply_take";
                break;
            case "ApplyStockOut":
                modelName = "apply_stockout";
                break;
            case "ApplyPurchase":
                modelName = "apply_purchase";
                break;
            case "ApplyStockBack":
                modelName = "apply_stockback";
                break;
            case "ApplyMaterialEdit":
                modelName = "apply_materialedit";
                break;
            case "SupplierPriceChange":
                modelName = "supplier_pricechange";
                break;
            case "StockCheckRecordDetail":
                modelName = "stock_checkrecorddetail";
                break;
            case "StockCheckQtyAdjust":
                modelName = "stock_checkqtyadjust";
                break;
        }


        String sql = "select ApproveBillState from " + modelName + " where ID = '" + linkId + "'";

        return baseMapper.getApproveType(sql);
    }

    private WrapperUtil getFlowWrapper(Map<String, String> condition) {
        return WrapperUtil.init(condition)
                .periodOfTime("fa.CreatedTime")
                .eq("fa.CheckState", "checkState");
    }

    /**
     * 获取时间段查询
     *
     * @param field     字段名称
     * @param condition 条件
     * @return
     */
    private QueryWrapper<Object> getDateWrapper(String field, Map<String, ?> condition) {
        if (ObjectUtil.isAllEmpty(condition.get("type"), condition.get("beginTime"), condition.get("endTime"))) {
            throw new ServiceException("日期不能为空");
        }
        int type = Integer.parseInt(condition.get("type").toString());
        Date date = new Date();
        Date beginDate;
        Date endDate;

        switch (type) {
            case 0: // 本日
                beginDate = DateUtil.beginOfDay(date);
                endDate = DateUtil.endOfDay(date);
                break;
            case 1: // 昨日
                beginDate = DateUtil.beginOfDay(DateUtil.offsetDay(date, -1));
                endDate = DateUtil.endOfDay(DateUtil.offsetDay(date, -1));
                break;
            case 2: // 本周
                beginDate = DateUtil.beginOfWeek(date);
                endDate = DateUtil.endOfWeek(date);
                break;
            case 3:  // 上周
                beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(date, -1));
                endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(date, -1));
                break;
            case 4: // 本月
                beginDate = DateUtil.beginOfMonth(date);
                endDate = DateUtil.endOfMonth(date);
                break;
            case 5: // 上月
                beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(date, -1));
                endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(date, -1));
                break;
            default: // 自定义
                beginDate = DateUtil.parse(condition.get("beginTime").toString());
                endDate = DateUtil.parse(condition.get("endTime").toString());
        }

        return Wrappers.query().between(field, beginDate, endDate);
    }

    private Map<String, String> selectPicking(Map<String, Object> condition) {
        Map<String, String> details = new HashMap<>();
        QueryWrapper<Object> wrapper = getDateWrapper("si.create_time", condition);
        wrapper.groupBy("si.scheduling_material", "si.job_no");
        List<Map<String, Object>> maps = baseMapper.selectPickingQuantitySum(wrapper);
        maps = maps.stream().filter(map -> ObjectUtil.isNotEmpty(map.get("technologyType"))).collect(Collectors.toList());
        for (Map<String, Object> map : maps) {
            details.put(map.get("technologyType").toString(), map.get("quantity").toString());
        }
        return details;
    }

}
