package com.sy.coinage.workshop.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.sy.coinage.core.constants.CacheKey;
import com.sy.coinage.core.exception.RetException;
import com.sy.coinage.core.redis.RedisService;
import com.sy.coinage.core.util.DateUtils;
import com.sy.coinage.core.vo.CacheUserVO;
import com.sy.coinage.log.model.LoginLog;
import com.sy.coinage.sys.model.Dept;
import com.sy.coinage.workshop.service.IStockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sy.coinage.workshop.dao.WorkshopAccountDao;
import com.sy.coinage.workshop.model.*;
import com.sy.coinage.workshop.service.IWorkshopAccountService;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * -ServiceImpl
 */
@Service
public class WorkshopAccountServiceImpl extends ServiceImpl<WorkshopAccountDao, WorkshopAccount>
        implements IWorkshopAccountService {

    @Autowired
    private IStockService stockService;

    @Autowired
    private RedisService redisService;

    @Override
    @Transactional
    public void shopOut(Integer redFlashFlag, Integer deptId, String dept, Integer operatorId,
                        String operator, Integer checkId, String checker, String orderNo,
                        Integer piecesTotal, Integer total, Integer statType, Integer type, String digest,
                        Integer wareId, Integer securitiesId, String securities) {
        // 插入车间台账表
        WorkshopAccount model = new WorkshopAccount();
        model.setStatType(statType);
        model.setDigest(digest);
        // 统计台账类型：1.实物收发卡 2.封箱成品实物收发卡(车间) 3.剔除品实物收发卡(车间) 4.印花成品出入库台账 5.封箱成品出入库台账
        if (statType == 2) {//  2.封箱成品实物收发卡(车间)
            // 付出(枚)
            if (type.intValue() == 1) {
                // 内部收入(枚) =拍子总枚数（拍子数量*每拍子箱子数量*每箱子枚数）
                model.setInnerPayQty(piecesTotal);
                // 1:普通 2:红冲数据（抽检、返检）
                if (redFlashFlag == 1) {
                    // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocFrom(3);
                    // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocTo(1);
                } else {
                    // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocFrom(3);
                    // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocTo(2);
                }
            } else {
                model.setPayQty(piecesTotal);
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(3);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocTo(1);
            }
        } else if (statType == 3) {// 3.剔除品实物收发卡(车间)
            // 内部收入(枚) =拍子总枚数（拍子数量*每拍子箱子数量*每箱子枚数）
            model.setInnerPayQty(piecesTotal);
            // 1:普通 2:红冲数据（抽检、返检）
            if (redFlashFlag == 1) {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(4);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                // FIXME 零箱零枚只能出库到机台
                model.setLocTo(2);
            }
        } else if (statType == 4) {// 4.印花成品出入库台账
            model.setPayQty(piecesTotal);
            if (redFlashFlag == 1) {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(5);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                // FIXME 零箱零枚只能出库到机台
                model.setLocTo(8);
            } else {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(8);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                // FIXME 零箱零枚只能出库到机台
                model.setLocTo(5);
            }
        } else if (statType == 5) {// 5.封箱成品出入库台账
            model.setPayQty(piecesTotal);
            if (redFlashFlag == 1) {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(8);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                // FIXME 零箱零枚只能出库到机台
                model.setLocTo(1);
            } else {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(8);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                // FIXME 零箱零枚只能出库到机台
                model.setLocTo(5);
            }
        } else if (statType == 1) {// 1.总库
            model.setPayQty(piecesTotal);
            if (redFlashFlag == 1) {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(1);
            } else {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(1);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                if (deptId == 2) {
                    model.setLocTo(6);
                } else if (deptId == 3) {
                    model.setLocTo(7);
                }
            }
        }
        model.setSecuritiesId(securitiesId);
        model.setSecurities(securities);
        model.setWareId(wareId);
        // 结存:实时实际库存数量（每笔需要进行增减计算）
        model.setInventory(total);
        // 红冲标识 1:普通 2:红冲数据（抽检、返检）
        model.setRedFlashFlag(redFlashFlag);
        model.setOrderNo(orderNo);
        model.setDeptId(deptId);
        model.setDept(dept);
        model.setOperatorId(operatorId);
        model.setOperator(operator);
        model.setCheckId(checkId);
        model.setChecker(checker);
        model.setCreateTime(new Date());
        this.save(model);
    }

    @Override
    public void shopIn(Integer redFlashFlag, Integer deptId, String dept, Integer operatorId,
                       String operator, Integer checkId, String checker, String orderNo, Integer piecesTotal,
                       Integer total, Integer statType, Integer type, String digest, Integer wareId,
                       Integer securitiesId, String securities) {
        // 插入车间台账表
        WorkshopAccount model = new WorkshopAccount();
        model.setStatType(statType);
        model.setDigest(digest);
        // 统计台账类型：1.实物收发卡 2.封箱成品实物收发卡(车间) 3.剔除品实物收发卡(车间) 4.印花成品出入库台账 5.封箱成品出入库台账
        if (statType == 2) {//  2.封箱成品实物收发卡(车间)
            if (type.intValue() == 1) {
                // 内部收入(枚) =拍子总枚数（拍子数量*每拍子箱子数量*每箱子枚数）
                model.setInnerIncomeQty(piecesTotal);
                if (redFlashFlag == 1) {
                    // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocFrom(2);
                    // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocTo(3);
                } else {
                    // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocFrom(1);
                    // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocTo(3);
                }
            } else {
                model.setIncomeQty(piecesTotal);
                if (redFlashFlag == 1) {
                    // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocFrom(2);
                    // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocTo(3);
                } else {
                    // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocFrom(1);
                    // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                    model.setLocTo(3);
                }
            }

        } else if (statType == 3) {// 3.剔除品实物收发卡(车间)
            // 内部收入(枚) =拍子总枚数（拍子数量*每拍子箱子数量*每箱子枚数）
            model.setInnerIncomeQty(piecesTotal);
            if (redFlashFlag == 1) {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(2);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocTo(4);
            } else {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(3);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocTo(4);
            }
        } else if (statType == 5) {// 3.剔除品实物收发卡(车间)
            model.setIncomeQty(piecesTotal);
            // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
            // 内部收入(枚) =拍子总枚数（拍子数量*每拍子箱子数量*每箱子枚数）
            model.setInnerIncomeQty(piecesTotal);
            if (redFlashFlag == 1) {
                model.setLocFrom(5);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocTo(8);
            } else {
                model.setLocFrom(1);
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocTo(8);
            }
        } else if (statType == 1) {// 1 实物收发卡
            model.setIncomeQty(piecesTotal);
            model.setDigest(dept);
            // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
            if (redFlashFlag == 1) {
                if (deptId == 2) {
                    model.setLocFrom(6);
                } else if (deptId == 3) {
                    model.setLocFrom(7);
                }
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocTo(1);
            } else {
                if (deptId == 2) {
                    model.setLocTo(6);
                } else if (deptId == 3) {
                    model.setLocTo(7);
                }
                // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(1);
            }
        } else if (statType == 4) {// 4.印花成品出入库台账
            model.setIncomeQty(piecesTotal);
            if (redFlashFlag == 1) {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(3);
                model.setLocTo(5);
            } else {
                // 来源地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
                model.setLocFrom(8);
                model.setLocTo(5);
            }
        }
        model.setSecuritiesId(securitiesId);
        model.setSecurities(securities);
        model.setWareId(wareId);
        // 结存:实时实际库存数量（每笔需要进行增减计算）
        // 红冲标识 1:普通 2:红冲数据（抽检、返检）
        model.setRedFlashFlag(redFlashFlag);
        model.setInventory(total);
        model.setDeptId(deptId);
        model.setDept(dept);
        model.setOperatorId(operatorId);
        model.setOperator(operator);
        model.setCheckId(checkId);
        model.setChecker(checker);
        model.setCreateTime(new Date());
        this.save(model);
    }

    @Override
    public void createAccount(Date d, CacheUserVO user) {
        Integer wareId = user.getSelfWareId();
        Stock lastStock = this.stockService.getLastStock(wareId);
        Stock stock = null;
        List<Stock> stockList = this.stockService.getStockList(wareId, lastStock.getSecuritiesId());
        for (Stock vo : stockList) {
            if (vo.getAreaId() == 1) {
                stock = vo;
            }
        }
        if (stock == null) {
            return;
        }
//        Date d = new Date();
        String key = "account_last_date:" + wareId;
        Date lastDate = this.getCacheDate(key);
        if (lastDate != null && lastDate.after(d)) {
            throw new RetException("不能生成" + DateUtils.toString(lastDate) + "之前的台账");
        }
        // 查询是否存在
        this.valid(d, user, stock);
        // 计算当日内部收入
        Integer innerIncomeQty = this.getInnerIncomeQty(d, stock.getSecuritiesId(), user, lastDate);
        // 计算当日内部付出
        Integer innerPayQty = this.getInnerPayQty(d, stock.getSecuritiesId(), user, lastDate);
        // 当日收
        Integer total = innerIncomeQty - innerPayQty;
        // 查询前日最后一条数据结存
        Integer inventory = total + getLastInventory(stock.getSecuritiesId(), user.getDeptId());
        // 增加
        WorkshopAccount model = new WorkshopAccount();
        model.setDeptId(user.getDeptId());
        model.setDept(user.getDept());
        model.setOperatorId(user.getId());
        model.setOperator(user.getRealName());
        model.setSecuritiesId(stock.getSecuritiesId());
        model.setSecurities(stock.getSecurities());
        model.setIncomeQty(total);
        model.setInventory(inventory);
        model.setRedFlashFlag(1);
        model.setCreateTime(DateUtils.getDayStartTime(d));
        model.setStatType(4);
        model.setLocFrom(3);
        model.setLocTo(5);
        model.setDigest("机台");
        this.save(model);
        // 缓存最后时间
        this.redisService.set(key, DateUtils.toString(d, DateUtils.YY_MM_DD_HH_mm_ss));
    }

    private Date getCacheDate(String key) {
        Date resp = null;
        try {
            if (redisService.hasKey(key)) {
                String json = redisService.get(key);
                resp = DateUtils.toDate(json, DateUtils.YY_MM_DD_HH_mm_ss);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resp;
    }


    @Override
    public Integer getLastInventory(Integer securitiesId, Integer deptId) {
        Integer total = 0;
        LambdaQueryWrapper<WorkshopAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopAccount::getDeptId, deptId);
//        queryWrapper.eq(WorkshopAccount::getRedFlashFlag, 1);
//        queryWrapper.between(WorkshopAccount::getCreateTime, DateUtils.getDayStartTime(d), DateUtils.getDayEndTime(d));
        queryWrapper.eq(WorkshopAccount::getSecuritiesId, securitiesId);
        queryWrapper.eq(WorkshopAccount::getStatType, 4);
        // 目的地 1: 总库2:机台 3:封箱成品4:剔除品 5:印花成品 6.造币二部 7造币三部 8 其他
//        queryWrapper.eq(WorkshopAccount::getLocFrom, 5);
        queryWrapper.orderByDesc(WorkshopAccount::getCreateTime);
        Page<WorkshopAccount> page = new Page<>(1, 1);
        IPage<WorkshopAccount> list = this.page(page, queryWrapper);
        if (list.getRecords() != null && list.getRecords().size() > 0) {
            total = list.getRecords().get(0).getInventory();
        }
        return total;
    }

    private Integer getInnerPayQty(Date d, Integer securitiesId, CacheUserVO user, Date lastDate) {
        Integer total = 0;
        LambdaQueryWrapper<WorkshopAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopAccount::getDeptId, user.getDeptId());
        queryWrapper.eq(WorkshopAccount::getRedFlashFlag, 1);
        if (lastDate != null) {
            queryWrapper.between(WorkshopAccount::getCreateTime, lastDate, DateUtils.getDayEndTime(d));
        } else {
            queryWrapper.le(WorkshopAccount::getCreateTime, d);
        }
        queryWrapper.eq(WorkshopAccount::getStatType, 3);
        queryWrapper.eq(WorkshopAccount::getLocFrom, 4);
        queryWrapper.eq(WorkshopAccount::getLocTo, 2);
        List<WorkshopAccount> list = this.list(queryWrapper);
        if (list != null && list.size() > 0) {
            total = list.stream().mapToInt(s -> s.getInnerPayQty()).sum();
        }
        return total;
    }

    private Integer getInnerIncomeQty(Date d, Integer securitiesId, CacheUserVO user, Date lastDate) {
        Integer total = 0;
        LambdaQueryWrapper<WorkshopAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopAccount::getDeptId, user.getDeptId());
        queryWrapper.eq(WorkshopAccount::getRedFlashFlag, 1);
//        queryWrapper.between(WorkshopAccount::getCreateTime, DateUtils.getDayStartTime(d), DateUtils.getDayEndTime(d));
        if (lastDate != null) {
            queryWrapper.between(WorkshopAccount::getCreateTime, lastDate, DateUtils.getDayEndTime(d));
        } else {
            queryWrapper.le(WorkshopAccount::getCreateTime, d);
        }
        queryWrapper.eq(WorkshopAccount::getSecuritiesId, securitiesId);
        queryWrapper.and(qw -> qw.eq(WorkshopAccount::getStatType, 2)).or().eq(WorkshopAccount::getStatType, 3);
        queryWrapper.eq(WorkshopAccount::getLocFrom, 2);
        List<WorkshopAccount> list = this.list(queryWrapper);
        if (list != null && list.size() > 0) {
            total = list.stream().mapToInt(s -> (s.getInnerIncomeQty() == null ? 0 : s.getInnerIncomeQty())).sum();
        }
        return total;
    }

    private void valid(Date d, CacheUserVO user, Stock stock) {
        LambdaQueryWrapper<WorkshopAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkshopAccount::getDeptId, user.getDeptId());
        queryWrapper.eq(WorkshopAccount::getRedFlashFlag, 1);
        queryWrapper.between(WorkshopAccount::getCreateTime, DateUtils.getDayStartTime(d), DateUtils.getDayEndTime(d));
        queryWrapper.eq(WorkshopAccount::getSecuritiesId, stock.getSecuritiesId());
        queryWrapper.eq(WorkshopAccount::getStatType, 4);
        queryWrapper.eq(WorkshopAccount::getLocTo, 5);
        queryWrapper.eq(WorkshopAccount::getLocFrom, 3);
        long count = this.count(queryWrapper);
        if (count > 0) {
            throw new RetException("当日台账已生成");
        }
    }

}
