package com.sy.coinage.workshop.component;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sy.coinage.core.constants.CacheKey;
import com.sy.coinage.core.constants.Constants;
import com.sy.coinage.core.redis.RedisService;
import com.sy.coinage.core.util.Arith;
import com.sy.coinage.core.util.DateUtils;
import com.sy.coinage.core.util.RandomUtil;
import com.sy.coinage.core.vo.OptVO;
import com.sy.coinage.sys.model.Dept;
import com.sy.coinage.sys.service.IDeptService;
import com.sy.coinage.sys.service.IDictService;
import com.sy.coinage.workshop.model.*;
import com.sy.coinage.workshop.service.*;
import com.sy.coinage.workshop.vo.ScreenDeptVO;
import com.sy.coinage.workshop.vo.ScreenProportionVO;
import com.sy.coinage.workshop.vo.ScreenWareVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class ScreenComponent {

    @Autowired
    private IDeliveryPlanService deliveryPlanService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IDeptService deptService;

    @Autowired
    private IStockService stockService;

    @Autowired
    private IProductService productService;

    @Autowired
    private IProductPlanService productPlanService;

    @Autowired
    private IWorkshopOutboundService workshopOutboundService;

    @Autowired
    private IDeliveryService deliveryService;

    @Autowired
    private IWorkshopAccountService workshopAccountService;

    @Autowired
    private IDictService dictyService;

    @Autowired
    private IScreenDataService screenDataService;

    @Autowired
    private IBaseInfoService baseInfoService;

    /**
     * 币种库存占比与出入库完成率
     */
    public void loadInventoryInfo() {
        Dept dept = deptService.getByName("造币二部");
        this.cacheProportionInfo();
        this.cacheSecuritiesInfo(dept);
    }

    /**
     * 总库与品名 库存 出入库
     */
    public void loadWareInfo() {
        Date date = new Date();
        Dept dept = deptService.getByName("造币二部");
        this.cacheWareList(date, dept);
        this.cacheDayList(date, dept);
    }

    public void loadDept() {
        Dept dept = deptService.getByName("造币二部");
        this.cacheDeptYield(dept);
    }

    /**
     * 缓存大屏昨日产能
     */
    public void cacheDeptYield(Dept dept) {
        Integer data = 0;
        Integer dataPer = 0;
        Date start = DateUtils.getBeginDayOfYesterday();
        Date end = DateUtils.getEndDayOfYesterDay();
        LambdaQueryWrapper<WorkshopAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopAccount::getDept, dept.getName());
        queryWrapper.eq(WorkshopAccount::getRedFlashFlag, 1);
        queryWrapper.between(WorkshopAccount::getCreateTime, start, end);
        queryWrapper.eq(WorkshopAccount::getLocFrom, 2);
        queryWrapper.eq(WorkshopAccount::getLocTo, 3);
        queryWrapper.eq(WorkshopAccount::getStatType, 2);
        List<WorkshopAccount> list = this.workshopAccountService.list(queryWrapper);
        if (list != null && list.size() > 0) {
            Product p = this.productService.getByCache(list.get(0).getSecuritiesId());
            // 累加内部收入
            dataPer = list.stream().mapToInt(s -> s.getInnerIncomeQty()).sum();
            data = dataPer / p.getAmountPerBox();
        }
        this.redisService.set(CacheKey.DEPT_YIELD_PER + "造币二部", String.valueOf(dataPer), CacheKey.EXPIRED_ONE_DAY);
        this.redisService.set(CacheKey.DEPT_YIELD + "造币二部", String.valueOf(data), CacheKey.EXPIRED_ONE_DAY);
    }

    private void cacheWareList(Date date, Dept dept) {
        // 取实物收发卡收入
        List<WorkshopAccount> accountListIn = this.workshopAccountList(1, date, dept);
        // 取实物收发卡付出
        List<WorkshopAccount> accountListOut = this.workshopAccountList(2, date, dept);
        List<Stock> stockList = this.getStockList(2);
        // 取手动管理的大屏数据
        List<ScreenWareVO> screenDataList = this.listScreenData();
        List<ScreenWareVO> list = new ArrayList<>();
        if (stockList != null && stockList.size() > 0) {
            for (Stock stock : stockList) {
                ScreenWareVO vo = new ScreenWareVO();
                vo.setWareCn(stock.getWareCn());
                vo.setSecurities(stock.getSecurities());
                vo.setDayInQty(0);
                vo.setDayOutQty(0);
                // 取每拍实际箱数
                LambdaQueryWrapper<BaseInfo> queryWrapper1 = new LambdaQueryWrapper<>();
                queryWrapper1.eq(BaseInfo::getLocWareId, stock.getWareId());
                queryWrapper1.eq(BaseInfo::getSecuritiesId, stock.getSecuritiesId());
//                / 生命周期状态:1初始登记 2:车间入库 3:车间出库 4:总库入库  5:主库抽检出库 6.车间抽检入库确认 7.车间抽检出库8 主库抽检返回确认 9返捡总库出库 10:返捡车间确认 11拆包 12：已发货 13:返回机台
                queryWrapper1.and(wq -> {
                    wq.eq(BaseInfo::getStatus, 4).or().eq(BaseInfo::getStatus, 8).or().eq(BaseInfo::getStatus, 11);
                });
                List<BaseInfo> l = this.baseInfoService.list(queryWrapper1);
                Integer tatalBox = 0;
                if (l != null && l.size() > 0) {
                    for (BaseInfo baseInfo : l) {
                        tatalBox = tatalBox + baseInfo.getQty();
                    }
                }
                vo.setQty(tatalBox);
//                vo.setQty((stock.getBoxNum() == null ? 0 : stock.getBoxNum()) + (stock.getRacketNum() == null ? 0 : stock.getRacketNum()) * p.getBoxAmount());
                Product p = this.productService.getByCache(stock.getSecuritiesId());
                if (accountListIn != null && accountListIn.size() > 0) {
                    Integer totalQty = accountListIn.stream().filter(item -> item.getWareId().intValue() == stock.getWareId().intValue() && item.getSecuritiesId().intValue() == stock.getSecuritiesId().intValue()).collect(Collectors.toList()).stream().mapToInt(item -> item.getIncomeQty()).sum();
                    vo.setDayInQty(totalQty / p.getAmountPerBox());
                }
                if (accountListOut != null && accountListOut.size() > 0) {
                    Integer totalQty = accountListOut.stream().filter(item -> item.getWareId().intValue() == stock.getWareId().intValue() && item.getSecuritiesId().intValue() == stock.getSecuritiesId().intValue()).collect(Collectors.toList()).stream().mapToInt(item -> item.getPayQty()).sum();
                    vo.setDayOutQty(totalQty / p.getAmountPerBox());
                }
                if (vo.getQty() + vo.getDayInQty() + vo.getDayOutQty() > 0) {
                    list.add(vo);
                }
                if (screenDataList != null && screenDataList.size() > 0) {
                    for (ScreenWareVO screenWareVO : list) {
                        if (vo.getSecurities().equals(screenWareVO.getSecurities()) && vo.getWareCn().equals(screenWareVO.getWareCn())) {
                            vo.setQty(vo.getQty() + (screenWareVO.getQty() == null ? 0 : screenWareVO.getQty()));
                            vo.setDayInQty(vo.getDayInQty() + (screenWareVO.getDayInQty() == null ? 0 : screenWareVO.getDayInQty()));
                            vo.setDayOutQty(vo.getDayOutQty() + (screenWareVO.getDayOutQty() == null ? 0 : screenWareVO.getDayOutQty()));
                        }
                    }
                }
            }
        }
        this.redisService.set("screen_ware", JSON.toJSONString(list));
    }

    private void cacheDayList(Date date, Dept dept) {
        // 取实物收发卡收入
        List<WorkshopAccount> accountListIn = this.workshopAccountList(1, date, dept);
        // 取实物收发卡付出
        List<WorkshopAccount> accountListOut = this.workshopAccountList(2, date, dept);
        List<Stock> stockList = this.getStockList(1);
        List<ScreenWareVO> list = new ArrayList<>();
        // 取手动管理的大屏数据
        List<ScreenWareVO> screenDataList = this.listScreenData();
        if (stockList != null && stockList.size() > 0) {
            for (Stock stock : stockList) {
                ScreenWareVO vo = new ScreenWareVO();
                vo.setSecurities(stock.getSecurities());
                vo.setDayInQty(0);
                vo.setDayOutQty(0);
                Product p = this.productService.getByCache(stock.getSecuritiesId());
                vo.setQty((stock.getBoxNum() == null ? 0 : stock.getBoxNum()) + (stock.getRacketNum() == null ? 0 : stock.getRacketNum()) * p.getBoxAmount());
                if (accountListIn != null && accountListIn.size() > 0) {
                    Integer totalQty = accountListIn.stream().filter(item -> item.getSecuritiesId().intValue() == stock.getSecuritiesId().intValue()).collect(Collectors.toList()).stream().mapToInt(item -> item.getIncomeQty()).sum();
                    vo.setDayInQty(totalQty / p.getAmountPerBox());
                }
                if (accountListOut != null && accountListOut.size() > 0) {
                    Integer totalQty = accountListOut.stream().filter(item -> item.getSecuritiesId().intValue() == stock.getSecuritiesId().intValue()).collect(Collectors.toList()).stream().mapToInt(item -> item.getPayQty()).sum();
                    vo.setDayOutQty(totalQty / p.getAmountPerBox());
                }
                if (vo.getQty() + vo.getDayInQty() + vo.getDayOutQty() > 0) {
                    list.add(vo);
                }
                if (screenDataList != null && screenDataList.size() > 0) {
                    for (ScreenWareVO screenWareVO : list) {
                        if (vo.getSecurities().equals(screenWareVO.getSecurities())) {
                            vo.setQty(vo.getQty() + (screenWareVO.getQty() == null ? 0 : screenWareVO.getQty()));
                            vo.setDayInQty(vo.getDayInQty() + (screenWareVO.getDayInQty() == null ? 0 : screenWareVO.getDayInQty()));
                            vo.setDayOutQty(vo.getDayOutQty() + (screenWareVO.getDayOutQty() == null ? 0 : screenWareVO.getDayOutQty()));
                        }
                    }
                }
            }
        }
        // 取手动管理的大屏数据
//        List<ScreenWareVO> screenDataList = this.listScreenData();
//        if (screenDataList != null && screenDataList.size() > 0) {
//            if (list != null && list.size() > 0) {
//                for (ScreenWareVO screenWareVO : list) {
//                    for (int i = screenDataList.size() - 1; i >= 0; i--) {
//                        ScreenWareVO vo = screenDataList.get(i);
//                        if (vo.getSecurities().equals(screenWareVO.getSecurities())) {
//                            screenDataList.remove(i);
//                            break;
//                        }
//                    }
//                }
//            }
//            list.addAll(screenDataList);
//        }
        this.redisService.set("screen_day", JSON.toJSONString(list));
    }

    // 取手动管理的大屏数据
    private List<ScreenWareVO> listScreenData() {
        LambdaQueryWrapper<ScreenData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ScreenData::getStatus, Constants.STATUS_USABLE);
        List<ScreenData> list = this.screenDataService.list(queryWrapper);
        List<ScreenWareVO> resp = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (ScreenData screenData : list) {
                ScreenWareVO vo = new ScreenWareVO();
                BeanUtils.copyProperties(screenData, vo);
                resp.add(vo);
            }
        }
        return resp;
    }

    /**
     * @param type 1品名分组 2库分库
     * @return
     */
    private List<Stock> getStockList(Integer type) {
        QueryWrapper<Stock> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("sum(racket_num) as racket_num, securities_id, sum(box_num) as box_num, ware_cn, ware_id, securities");
        queryWrapper.gt(" ware_id", 200);
//        queryWrapper.and(wq -> {
//            wq.gt("racket_num", 0).or().gt("box_num", 0);
//        });
        if (type == 1) {
            queryWrapper.groupBy("securities_id");
        } else {
            queryWrapper.groupBy("securities_id,ware_cn");
        }
        queryWrapper.orderByAsc("ware_id").orderByAsc("securities");
        List<Stock> resp = this.stockService.list(queryWrapper);
        return resp;
    }

    private void cacheProportionInfo() {
        Integer proportion1 = 0;
        Integer proportion2 = 0;
        List<OptVO> list = dictyService.opt("wareRatioOpt", null);
        // 库总容量
        Integer total = list.stream().mapToInt(s -> Integer.parseInt(s.getVal())).sum();
        List<Stock> stock = this.getStockList(1);
        if (stock != null && stock.size() > 0) {
            for (Stock stock1 : stock) {
                Product p = this.productService.getByCache(stock1.getSecuritiesId());
                if(p == null){
                    p = this.productService.getById(stock1.getSecuritiesId());
                    log.info("cacheProportionInfo: product is:{} ,stock1.getSecuritiesId():{}",JSON.toJSONString(p),stock1.getSecuritiesId());
                }
                // 1 纪念币 2 流通币
                if (p.getTag() == 1) {
                    proportion1 = proportion1 + (stock1.getBoxNum() == null ? 0 : stock1.getBoxNum()) + stock1.getRacketNum() * p.getBoxAmount();
                } else {
                    proportion2 = proportion2 + (stock1.getBoxNum() == null ? 0 : stock1.getBoxNum()) + stock1.getRacketNum() * p.getBoxAmount();
                }
            }
        }
        ScreenProportionVO info = new ScreenProportionVO();
        info.setProportionStr1("纪念币库存占比");
        info.setProportion1(Arith.div(proportion1 * 100, total, 2));
        info.setProportionStr2("流通币库存占比");
        info.setProportion2(Arith.div(proportion2 * 100, total, 2));
        this.redisService.set("screen_proportion", JSON.toJSONString(info));
    }

    private void cacheSecuritiesInfo(Dept dept) {
        List<ProductPlan> list = this.productPlanService.cacheList();
        ScreenDeptVO data = new ScreenDeptVO();
        if (list != null && list.size() > 0) {
            List<String> securities = list.stream().map(item -> item.getSecurities()).collect(Collectors.toList());
            data.setName(securities);
            List<Double> production = new ArrayList<>();
            List<Double> inventory = new ArrayList<>();
            // 获取所有解缴单
            for (ProductPlan productPlan : list) {
                Integer totalBox = this.getTotalBox(productPlan.getCrownFrom(), productPlan.getCrownTo());
                List<WorkshopOutbound> out = this.outList(productPlan.getProductId(), productPlan.getCreateTime(), dept.getId());
                if (out != null && out.size() > 0 && totalBox > 0) {
                    // 取合计箱数
                    Integer total = out.stream().mapToInt(s -> s.getTotalBoxAmount()).sum();
                    // Integer r = total * 100 / totalBox;
                    Double r = Arith.div(total * 100, totalBox, 2);
                    production.add(r);
                } else {
                    production.add(0D);
                }
                // 获取所有发货计划
                Integer totalPalnBox = this.deliveryPlanTotal(productPlan.getProductId());
                // 获取所有发货单
                List<Delivery> delivery = this.deliveryList(productPlan.getProductId(), productPlan.getCreateTime());
                if (delivery != null && delivery.size() > 0 && totalPalnBox > 0) {
                    // 取合计箱数
                    Integer total = delivery.stream().mapToInt(s -> s.getPlanTotalBox()).sum();
//                    Integer r = total * 100 / totalPalnBox;
                    Double r = Arith.div(total * 100, totalPalnBox, 2);
                    inventory.add(r);
                } else {
                    inventory.add(0D);
                }
            }
            data.setProduction(production);
            data.setInventory(inventory);
        }
        this.redisService.set("screen_securities", JSON.toJSONString(data));
    }

    private Integer getTotalBox(String crownFrom, String crownTo) {
        Integer resp = 0;
        String[] crownArrFrom = crownFrom.split("-");
        String[] crownArrTo = crownTo.split("-");
        Integer firstCrownFrom = Integer.parseInt(crownArrFrom[0]);
        Integer lastCrownFrom = Integer.parseInt(crownArrFrom[1]);
        Integer firstCrownTo = Integer.parseInt(crownArrTo[0]);
        Integer lastCrownTo = Integer.parseInt(crownArrTo[1]);
        if (firstCrownFrom.intValue() == firstCrownTo.intValue()) {
            resp = lastCrownTo - lastCrownFrom + 1;
        } else if (firstCrownTo - firstCrownFrom > 1) {
            Integer firmstQty = firstCrownTo - firstCrownFrom - 1;
            resp = 5000 - lastCrownFrom + 1 + lastCrownTo + firmstQty * 5000;
        } else if (firstCrownTo - firstCrownFrom == 1) {
            resp = 5000 - lastCrownFrom + 1 + lastCrownTo;
        }
        return resp;
    }


    private Integer deliveryPlanTotal(Integer securitiesId) {
        Integer resp = 0;
        LambdaQueryWrapper<DeliveryPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliveryPlan::getSecuritiesId, securitiesId);
        queryWrapper.orderByDesc(DeliveryPlan::getId);
        List<DeliveryPlan> list = this.deliveryPlanService.list(queryWrapper);
        if (list != null && list.size() > 0) {
            // 取合计箱数
            resp = list.stream().mapToInt(s -> s.getTotalBoxNum()).sum();
        }
        return resp;
    }


    private List<Delivery> deliveryList(Integer securitiesId, Date createTime) {
        LambdaQueryWrapper<Delivery> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Delivery::getSecuritiesId, securitiesId);
        // 发货单状态  1:初始化 2 已发货
        queryWrapper.eq(Delivery::getStatus, 2);
        queryWrapper.gt(Delivery::getDeliveryTime, createTime);
        return this.deliveryService.list(queryWrapper);
    }

    private List<WorkshopOutbound> outList(Integer securitiesId, Date createTime, Integer deptId) {
        LambdaQueryWrapper<WorkshopOutbound> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopOutbound::getSecuritiesId, securitiesId);
        queryWrapper.eq(WorkshopOutbound::getDeptId, deptId);
        // 单据类型： 1: 解缴单  2: 返捡单
        queryWrapper.eq(WorkshopOutbound::getOrderType, 1);
        // 状态:1.新建 2.已出库 3.已入库
        queryWrapper.eq(WorkshopOutbound::getStatus, 3);
        queryWrapper.gt(WorkshopOutbound::getCreateTime, createTime);

        return this.workshopOutboundService.list(queryWrapper);
    }

    /**
     * @param type 1入库 2发货
     * @param date
     * @param dept
     * @return
     */
    public List<WorkshopAccount> workshopAccountList(int type, Date date, Dept dept) {
        LambdaQueryWrapper<WorkshopAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopAccount::getRedFlashFlag, 1);
        if (type == 1) {
            queryWrapper.eq(WorkshopAccount::getDeptId, dept.getId());
            queryWrapper.eq(WorkshopAccount::getLocTo, 1);
        } else {
            queryWrapper.eq(WorkshopAccount::getLocFrom, 1);
        }
        // 实物收发卡
        queryWrapper.eq(WorkshopAccount::getStatType, 1);
        queryWrapper.between(WorkshopAccount::getCreateTime, DateUtils.getDayStartTime(date), DateUtils.getDayEndTime(date));
        List<WorkshopAccount> list = this.workshopAccountService.list(queryWrapper);
        return list;
    }

}
