/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.depotWork.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.biz.core.Const.BizStr;
import vip.xiaonuo.biz.modular.depotGrain.service.DepotGrainService;
import vip.xiaonuo.biz.modular.depotLoanGrant.entity.DepotLoanGrantDetailVo;
import vip.xiaonuo.biz.modular.depotLoanGrant.service.DepotLoanGrantService;
import vip.xiaonuo.biz.modular.depotSampling.entity.DepotSampling;
import vip.xiaonuo.biz.modular.depotSampling.service.DepotSamplingService;
import vip.xiaonuo.biz.modular.depotTruckLade.entity.DepotTruckLade;
import vip.xiaonuo.biz.modular.depotTruckLade.service.DepotTruckLadeService;
import vip.xiaonuo.biz.modular.depotTruckWeighDouble.param.StatisticsParam;
import vip.xiaonuo.biz.modular.depotTruckWeighDouble.service.DepotTruckWeighDoubleService;
import vip.xiaonuo.biz.modular.depotWork.entity.DepotWorkDetailGroupVo;
import vip.xiaonuo.biz.modular.depotWork.stats.DepotWorkStatsDateVo;
import vip.xiaonuo.biz.modular.depotWork.stats.DepotWorkStatsVo;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.modular.depotWork.entity.DepotWork;
import vip.xiaonuo.biz.modular.depotWork.mapper.DepotWorkMapper;
import vip.xiaonuo.biz.modular.depotWork.param.DepotWorkAddParam;
import vip.xiaonuo.biz.modular.depotWork.param.DepotWorkEditParam;
import vip.xiaonuo.biz.modular.depotWork.param.DepotWorkIdParam;
import vip.xiaonuo.biz.modular.depotWork.param.DepotWorkPageParam;
import vip.xiaonuo.common.util.BigDecimalUtil;
import vip.xiaonuo.common.util.DatesUtil;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 出入库管理表Service接口实现类
 *
 * @author xiang
 * @date 2023/09/18 10:20
 **/
@Service
public class DepotWorkService extends ServiceImpl<DepotWorkMapper, DepotWork> {

    @Resource
    DepotGrainService depotGrainService;

    public Page<DepotWork> page(DepotWorkPageParam param) {
        QueryWrapper<DepotWork> wrapper = new QueryWrapper<>();
        List<String> depotIdLst = depotGrainService.lstOrgGrep();
        wrapper.lambda().in(CollUtil.isNotEmpty(depotIdLst), DepotWork::getDepotId, depotIdLst);
        wrapper.lambda().eq(ObjectUtil.isNotEmpty(param.getDepotId()), DepotWork::getDepotId, param.getDepotId());
        wrapper.lambda().eq(Strings.isNotBlank(param.getRepayOrderNo()), DepotWork::getRepayOrderNo, param.getRepayOrderNo());
        wrapper.lambda().eq(Strings.isNotBlank(param.getLoanOrderNo()), DepotWork::getLoanOrderNo, param.getLoanOrderNo());
        wrapper.lambda().eq(Strings.isNotBlank(param.getLoanState()), DepotWork::getLoanState, param.getLoanState());
        if (ObjectUtil.isNotEmpty(param.getDepotBizType())) {
            wrapper.lambda().eq(DepotWork::getDepotBizType, param.getDepotBizType());
        }
        if (ObjectUtil.isNotEmpty(param.getKeeperCitizenId())) {
            wrapper.lambda().like(DepotWork::getKeeperCitizenId, param.getKeeperCitizenId());
        }
        wrapper.lambda().eq(ObjectUtil.isNotEmpty(param.getGrainGroup()), DepotWork::getGrainGroup, param.getGrainGroup());
        if (ObjectUtil.isNotEmpty(param.getLicensePlate())) {
            wrapper.lambda().like(DepotWork::getLicensePlate, param.getLicensePlate());
        }
        if (ObjectUtil.isAllNotEmpty(param.getSortField(), param.getSortOrder())) {
            CommonSortOrderEnum.validate(param.getSortOrder());
            wrapper.orderBy(true, param.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(param.getSortField()));
        } else {
            wrapper.lambda().orderByDesc(DepotWork::getId);
        }
        Page page = this.page(CommonPageRequest.defaultPage(), wrapper);
        //匹配粮库名称
        depotGrainService.putDepotName(page.getRecords());
        return page;
    }

    public List<DepotWork> lst(DepotWorkPageParam param) {
        LambdaQueryWrapper<DepotWork> wrapper = new LambdaQueryWrapper<>(BeanUtil.toBean(param, DepotWork.class));
        List<String> depotIdLst = depotGrainService.lstOrgGrep();
        wrapper.in(CollUtil.isNotEmpty(depotIdLst), DepotWork::getDepotId, depotIdLst);
        if (ObjectUtil.isNotEmpty(param.getStartCreateTime()) && ObjectUtil.isNotEmpty(param.getEndCreateTime()))
            wrapper.between(DepotWork::getCreateTime, param.getStartCreateTime(), param.getEndCreateTime());
        List<DepotWork> list = list(wrapper);
        //匹配粮库名称
        depotGrainService.putDepotName(list);
        return list;
    }

    public List<DepotWork> lst(List<String> idLst) {
        LambdaQueryWrapper<DepotWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(DepotWork::getId, idLst);
        return list(wrapper);
    }

    /**
     * 放款入库记录
     *
     * @param repayOrderNo 还款单号
     * @param loanOrderNo  放款单号
     * @author xiang
     * @date 2023/09/18 10:20
     **/
    public List<DepotWork> lst(String repayOrderNo, String loanOrderNo) {
        if (ArrayUtil.isAllEmpty(repayOrderNo, loanOrderNo)) return new ArrayList<>();
        return list(new LambdaQueryWrapper<>(new DepotWork(repayOrderNo, loanOrderNo)));
    }

    public List<DepotWork> lst(StatisticsParam param) {
        LambdaQueryWrapper<DepotWork> wrapper = new LambdaQueryWrapper<>();
        List<String> depotIdLst = depotGrainService.lstOrgGrep();
        wrapper.in(CollUtil.isNotEmpty(depotIdLst), DepotWork::getDepotId, depotIdLst);
        wrapper.ge(Strings.isNotBlank(param.getDepotId()), DepotWork::getDepotId, param.getDepotId());
        wrapper.ge(Strings.isNotBlank(param.getCreateTimeStart()), DepotWork::getCreateTime, param.getCreateTimeStart());
        wrapper.le(Strings.isNotBlank(param.getCreateTimeEnd()), DepotWork::getCreateTime, param.getCreateTimeEnd());
        return list(wrapper);
    }

    public DepotWork oneByBookId(String bookId) {
        LambdaQueryWrapper<DepotWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DepotWork::getTruckBookId, bookId);
        return getOne(wrapper);
    }

    public DepotWork add(DepotWorkAddParam depotWorkAddParam) {
        DepotWork depotWork = BeanUtil.toBean(depotWorkAddParam, DepotWork.class);
        this.save(depotWork);
        return depotWork;
    }

    public void edit(DepotWorkEditParam depotWorkEditParam) {
        DepotWork depotWork = this.queryEntity(depotWorkEditParam.getId());
        BeanUtil.copyProperties(depotWorkEditParam, depotWork);
        this.updateById(depotWork);
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(List<DepotWorkIdParam> depotWorkIdParamList) {
        // 执行删除
        this.removeBatchByIds(CollStreamUtil.toList(depotWorkIdParamList, DepotWorkIdParam::getId));
    }

    public DepotWork detail(DepotWorkIdParam depotWorkIdParam) {
        return this.queryEntity(depotWorkIdParam.getId());
    }

    public DepotWork detail(String id, String bookId) {
        DepotWork work = null;
        if (id != null)
            work = this.queryEntity(id);
        else if (bookId != null)
            work = this.oneByBookId(bookId);
        if (work != null) {
            work.setDepotGrainName(depotGrainService.getNameByDepotId(work.getDepotId()));
            //放款审批人
            if (BizStr.STATE_LOAN_GRANT_Y.equals(work.getLoanState()) && Strings.isNotBlank(work.getLoanOrderNo())) {
                //放款审批员
                DepotLoanGrantDetailVo depotLoanGrant = depotLoanGrantService.detail(null, work.getLoanOrderNo());
                if (depotLoanGrant != null) {
                    work.setApprovalUserName(depotLoanGrant.getApprovalUserName());
                    work.setApprovalUserAccount(depotLoanGrant.getApprovalUserAccount());
                }
            }
        } else {
            work = new DepotWork();
        }
        return work;
    }

    @Resource
    DepotSamplingService depotSamplingService;
    @Resource
    DepotTruckLadeService depotTruckLadeService;
    @Resource
    DepotTruckWeighDoubleService depotTruckWeighDoubleService;
    @Resource
    DepotLoanGrantService depotLoanGrantService;

    public DepotWorkDetailGroupVo detailGroup(String truckBookId) {
        DepotWorkDetailGroupVo vo = new DepotWorkDetailGroupVo();
        vo.setDepotWork(detail(null, truckBookId));
        vo.setDepotSampling(depotSamplingService.detail(new DepotSampling(truckBookId)));
        vo.setDepotTruckLade(depotTruckLadeService.detail(new DepotTruckLade(truckBookId)));
        vo.setDepotTruckWeighDouble(depotTruckWeighDoubleService.detail(null, truckBookId));
        return vo;
    }

    public DepotWork queryEntity(String id) {
        DepotWork depotWork = this.getById(id);
        if (ObjectUtil.isEmpty(depotWork)) {
            throw new CommonException("出入库管理表不存在，id值为：{}", id);
        }
        return depotWork;
    }

    /**
     * 放款同步入库记录
     *
     * @param loanOrderNo 放款单号
     * @param idLst       记录id
     * @param loanState   放款状态
     * @author xiang
     * @date 2023/09/18 10:20
     **/
    @Transactional(rollbackFor = Exception.class)
    public void loanGrant(String loanOrderNo, List<String> idLst, String loanState) {
        if (ArrayUtil.hasEmpty(loanOrderNo, loanState)) return;
        LambdaUpdateWrapper<DepotWork> wrapper = new LambdaUpdateWrapper<>();
        if (CollUtil.isNotEmpty(idLst)) {
            wrapper.in(DepotWork::getId, idLst);
            wrapper.set(DepotWork::getLoanOrderNo, loanOrderNo);
        } else {
            wrapper.eq(DepotWork::getLoanOrderNo, loanOrderNo);
        }
        wrapper.set(DepotWork::getLoanState, loanState);
        update(wrapper);
    }

    /**
     * 出入库统计
     *
     * @param param 范围
     * @author xiang
     * @date 2023/09/18 10:20
     **/
    public Object statsDate(StatisticsParam param) {

        DepotWorkStatsVo result = new DepotWorkStatsVo();
        List<String> dateLst = null;
        //时间范围
        String startDate = null;
        String endDate = null;
        if (param.getCreateTimeStart() != null && param.getCreateTimeStart().length() == 10) {
            startDate = param.getCreateTimeStart();
            param.setCreateTimeStart(param.getCreateTimeStart() + " 00:00:00");
            param.setType(6);
        }
        if (param.getCreateTimeEnd() != null && param.getCreateTimeEnd().length() == 10) {
            endDate = param.getCreateTimeEnd();
            param.setCreateTimeEnd(param.getCreateTimeEnd() + " 23:59:59");
            param.setType(6);
        }
        if (param.getType() != 6) {
            startDate = DatesUtil.forDateTime(DatesUtil.getStartTime(new Date(), param.getType()));
            endDate = DatesUtil.forDateTime(DatesUtil.getEndTime(new Date(), param.getType()));
            dateLst = DatesUtil.dateBetween(startDate, endDate, param.getType() > 3 ? 7 : param.getType() == 1 ? 13 : 10);
            param.setCreateTimeStart(startDate);
            param.setCreateTimeEnd(endDate);
        }
        //出入库记录
        List<DepotWork> works = lst(param);
        if (param.getType() == 6) {
            if (startDate == null && !works.isEmpty())
                startDate = DatesUtil.forDateTime(works.get(0).getCreateTime()).substring(0, 4);
            if (endDate == null && !works.isEmpty())
                endDate = DatesUtil.forDateTime(works.get(works.size() - 1).getCreateTime()).substring(0, 4);
            dateLst = DatesUtil.dateBetween(startDate, endDate, 4);
        }
        //总入库 总入库折算
        BigDecimal inSurplusSum = BigDecimal.ZERO, inDrySurplusSum = BigDecimal.ZERO;
        for (String dateOne : dateLst) {
            List<DepotWork> workTimeStream = works.stream().filter(
                    s -> DatesUtil.forDateTime(s.getCreateTime()).contains(dateOne)).collect(Collectors.toList());
            DepotWorkStatsDateVo vo = new DepotWorkStatsDateVo(dateOne, workTimeStream.size());
            result.getDateVos().add(vo);
            for (DepotWork workTime : workTimeStream) {
                //日期_总毛重
                vo.setGrossWeightSum(BigDecimalUtil.addVal(vo.getGrossWeightSum(), workTime.getGrossWeight()));
                //日期_总皮重
                vo.setTareWeightSum(BigDecimalUtil.addVal(vo.getTareWeightSum(), workTime.getTareWeight()));
                //日期_总净重
                vo.setNetWeightSum(BigDecimalUtil.addVal(vo.getNetWeightSum(), workTime.getNetWeight()));
                //日期_入库
                if (BizStr.KU_RU.equals(workTime.getDepotBizType())) {
                    vo.setInSurplusSum(BigDecimalUtil.addVal(vo.getInSurplusSum(), workTime.getDepotTonCount().movePointRight(3)));
                    inDrySurplusSum = BigDecimalUtil.addVal(inDrySurplusSum, workTime.getDryTonCount().movePointRight(3));
                }
                //日期_出库
                else if (BizStr.KU_CHU.equals(workTime.getDepotBizType())) {
                    vo.setOutSurplusSum(BigDecimalUtil.addVal(vo.getOutSurplusSum(), workTime.getDepotTonCount().movePointRight(3)));
                }
            }
            //总毛重
            result.setGrossWeightSum(BigDecimalUtil.addVal(result.getGrossWeightSum(), vo.getGrossWeightSum()));
            //总皮重
            result.setTareWeightSum(BigDecimalUtil.addVal(result.getTareWeightSum(), vo.getTareWeightSum()));
            //总净重
            result.setNetWeightSum(BigDecimalUtil.addVal(result.getNetWeightSum(), vo.getNetWeightSum()));
            //总车次
            result.setTruckSum(result.getTruckSum() + vo.getTruckSum());
            //总入库
            //result.setInSurplusSum(BigDecimalUtil.addVal(result.getInSurplusSum(), vo.getInSurplusSum()));
            inSurplusSum = BigDecimalUtil.addVal(inSurplusSum, vo.getInSurplusSum());
            //总出库
            result.setOutSurplusSum(BigDecimalUtil.addVal(result.getOutSurplusSum(), vo.getOutSurplusSum()));
        }
        result.setInSurplusSum(String.format("%s/%s", inSurplusSum, inDrySurplusSum));
        //总库存
        result.setSurplusSum(BigDecimalUtil.addVal(inSurplusSum, result.getOutSurplusSum().negate()));

        return result;
    }
}
