/*
 * 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.depotLoanGrant.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
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.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.auth.modular.login.service.AuthService;
import vip.xiaonuo.biz.core.Const.BizStr;
import vip.xiaonuo.biz.core.exception.BizExceptionEnum;
import vip.xiaonuo.biz.modular.depotGrain.service.DepotGrainService;
import vip.xiaonuo.biz.modular.depotGrainInfo.entity.DepotGrainInfo;
import vip.xiaonuo.biz.modular.depotGrainInfo.service.DepotGrainInfoService;
import vip.xiaonuo.biz.modular.depotGrainInfoPrice.service.DepotGrainInfoPriceService;
import vip.xiaonuo.biz.modular.depotLoanGrant.entity.DepotLoanGrantDetailVo;
import vip.xiaonuo.biz.modular.depotLoanGrant.param.*;
import vip.xiaonuo.biz.modular.depotWork.entity.DepotWork;
import vip.xiaonuo.biz.modular.depotWork.service.DepotWorkService;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.modular.depotLoanGrant.entity.DepotLoanGrant;
import vip.xiaonuo.biz.modular.depotLoanGrant.mapper.DepotLoanGrantMapper;
import vip.xiaonuo.common.util.BigDecimalUtil;
import vip.xiaonuo.common.util.DatesUtil;
import vip.xiaonuo.sys.modular.user.entity.SysUser;
import vip.xiaonuo.sys.modular.user.service.SysUserService;

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

/**
 * 入库放款单Service接口实现类
 *
 * @author xiang
 * @date 2023/09/18 16:03
 **/
@Service
public class DepotLoanGrantService extends ServiceImpl<DepotLoanGrantMapper, DepotLoanGrant> {

    @Resource
    DepotGrainService depotGrainService;
    @Resource
    DepotWorkService depotWorkService;
    @Resource
    DepotGrainInfoService depotGrainInfoService;
    @Resource
    DepotGrainInfoPriceService depotGrainInfoPriceService;
    @Resource
    AuthService authService;

    public Page<DepotLoanGrant> page(DepotLoanGrantPageParam param) {
        QueryWrapper<DepotLoanGrant> wrapper = new QueryWrapper<>();
        List<String> depotIdLst = depotGrainService.lstOrgGrep();
        wrapper.lambda().in(CollUtil.isNotEmpty(depotIdLst), DepotLoanGrant::getDepotId, depotIdLst);
        if (ObjectUtil.isNotEmpty(param.getDepotId())) {
            wrapper.lambda().eq(DepotLoanGrant::getDepotId, param.getDepotId());
        }
        if (ObjectUtil.isNotEmpty(param.getContractCode())) {
            wrapper.lambda().like(DepotLoanGrant::getContractCode, param.getContractCode());
        }
        wrapper.lambda().like(Strings.isNotBlank(param.getLoanOrderNo()), DepotLoanGrant::getLoanOrderNo, param.getLoanOrderNo());
        wrapper.lambda().eq(Strings.isNotBlank(param.getGrainGroup()), DepotLoanGrant::getGrainGroup, param.getGrainGroup());
        wrapper.lambda().eq(Strings.isNotBlank(param.getLoanState()), DepotLoanGrant::getLoanState, param.getLoanState());
        wrapper.lambda().eq(Strings.isNotBlank(param.getBankOpApprovalState()), DepotLoanGrant::getBankOpApprovalState, param.getBankOpApprovalState());
        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(DepotLoanGrant::getId);
        }
        Page page = this.page(CommonPageRequest.defaultPage(), wrapper);
        //匹配粮库名称
        depotGrainService.putDepotName(page.getRecords());
        //人员信息
        putUserInfo(page.getRecords());
        return page;
    }

    private void putUserInfo(List<DepotLoanGrant> list) {
        if (list.isEmpty()) return;
        List<String> userIds = new LinkedList<>();
        list.forEach(one -> {
            if (Strings.isNotBlank(one.getApprovalUser()))
                userIds.add(one.getApprovalUser());
            if (Strings.isNotBlank(one.getCreateUser()))
                userIds.add(one.getCreateUser());
        });
        if (userIds.isEmpty()) return;
        List<SysUser> users = sysUserService.listByIds(userIds);
        for (DepotLoanGrant one : list) {
            //审批人
            if (Strings.isNotBlank(one.getApprovalUser()))
                for (SysUser user : users) {
                    if (!one.getApprovalUser().equals(user.getId())) continue;
                    one.setApprovalUserName(user.getName());
                    one.setApprovalUserAccount(user.getAccount());
                    break;
                }
            //创建人
            if (Strings.isNotBlank(one.getCreateUser()))
                for (SysUser user : users) {
                    if (!one.getCreateUser().equals(user.getId())) continue;
                    one.setCreateUserName(user.getName());
                    one.setCreateUserAccount(user.getAccount());
                    break;
                }
        }
    }

    public List<DepotLoanGrant> lst(DepotLoanGrantPageParam param) {
        LambdaQueryWrapper<DepotLoanGrant> wrapper = new LambdaQueryWrapper<>(BeanUtil.toBean(param, DepotLoanGrant.class));
        wrapper.in(CollUtil.isNotEmpty(param.getIdLst()), DepotLoanGrant::getId, param.getIdLst());
        return list(wrapper);
    }

    /**
     * 获取待处理
     *
     * @author xiang
     * @date 2023/09/13 09:21
     */
    public List<DepotLoanGrant> waitProcess(List<String> depotIdLst) {
        LambdaQueryWrapper<DepotLoanGrant> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CollUtil.isNotEmpty(depotIdLst), DepotLoanGrant::getDepotId, depotIdLst);
        wrapper.eq(DepotLoanGrant::getBankOpApprovalState, BizStr.STATE_APPROVAL_N);
        return list(wrapper.orderByDesc(DepotLoanGrant::getId));
    }

    public List<DepotLoanGrant> lst(DepotLoanGrant param) {
        return list(new LambdaQueryWrapper<>(param));
    }

    @Transactional(rollbackFor = Exception.class)
    public void add(DepotLoanGrantAddParam param) {
        DepotGrainInfo info = depotGrainInfoService.oneByDepotId(param.getDepotId());
        //检查贷款超额
        checkLoanExcess(info, param.getLoanAmount());
        //检查贷款过期
        checkLoanOverDate(info.getLoanEndDate());
        //检查粮食种类
        depotGrainInfoPriceService.checkGrainGroup(param.getDepotId(), param.getGrainGroup());
        //检查贷放款状态
        checkWorkIdLst(param.getWorkIdLst());
        DepotLoanGrant depotLoanGrant = BeanUtil.toBean(param, DepotLoanGrant.class);
        depotLoanGrant.setLoanTruckCount(param.getWorkIdLst().size());
        this.save(depotLoanGrant);
        //放款申请同步入库记录
        depotWorkService.loanGrant(depotLoanGrant.getLoanOrderNo(), param.getWorkIdLst(), param.getLoanState());
        //放款申请同步客户信息
        depotGrainInfoService.loanSyncCheck(info, depotLoanGrant.getOrderWeight(), new BigDecimal(param.getWorkIdLst().size()));
    }

    public void edit(DepotLoanGrantEditParam depotLoanGrantEditParam) {
        DepotLoanGrant depotLoanGrant = this.queryEntity(depotLoanGrantEditParam.getId());
        BeanUtil.copyProperties(depotLoanGrantEditParam, depotLoanGrant);
        this.updateById(depotLoanGrant);
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(List<DepotLoanGrantIdParam> depotLoanGrantIdParamList) {
        DepotLoanGrantPageParam param = new DepotLoanGrantPageParam(CollStreamUtil.toList(depotLoanGrantIdParamList, DepotLoanGrantIdParam::getId), BizStr.STATE_APPROVAL_Y);
        if (!lst(param).isEmpty())
            throw new CommonException(BizExceptionEnum.ERROR12001.getMessage());
        List<DepotLoanGrant> grants = listByIds(param.getIdLst());
        // 执行删除
        this.removeBatchByIds(param.getIdLst());
        //放款同步入库记录
        for (DepotLoanGrant grant : grants) {
            depotWorkService.loanGrant(grant.getLoanOrderNo(), null, BizStr.STATE_LOAN_GRANT_N);
        }
    }

    @Resource
    SysUserService sysUserService;

    public DepotLoanGrantDetailVo detail(DepotLoanGrantIdParam param) {
        return detail(param.getId(), null);
    }

    public DepotLoanGrantDetailVo detail(String id, String loanOrderNo) {
        DepotLoanGrantDetailVo vo = null;
        if (Strings.isNotBlank(id))
            vo = BeanUtil.toBean(this.queryEntity(id), DepotLoanGrantDetailVo.class);
        if (vo == null && Strings.isNotBlank(loanOrderNo))
            vo = BeanUtil.toBean(this.getOneByOrderNo(loanOrderNo), DepotLoanGrantDetailVo.class);
        if (vo != null) {
            vo.setDepotGrainName(depotGrainService.getNameByDepotId(vo.getDepotId()));
            vo.setDepotWorkList(depotWorkService.lst(null, vo.getLoanOrderNo()));
            SysUser sysUser = sysUserService.getOneById(vo.getApprovalUser());
            if (sysUser != null) {
                vo.setApprovalUserName(sysUser.getName());
                vo.setApprovalUserAccount(sysUser.getAccount());
            }
        }
        return vo;
    }

    public DepotLoanGrant getOneByOrderNo(String orderNo) {
        DepotLoanGrant depotLoanGrant = getOne(new LambdaQueryWrapper<>(BeanUtil.toBean(new DepotLoanGrantPageParam(orderNo), DepotLoanGrant.class)));
        if (ObjectUtil.isEmpty(depotLoanGrant)) {
            throw new CommonException("入库放款单不存在，订单号值为：{}", orderNo);
        }
        return depotLoanGrant;
    }

    public DepotLoanGrant queryEntity(String id) {
        DepotLoanGrant depotLoanGrant = this.getById(id);
        if (ObjectUtil.isEmpty(depotLoanGrant)) {
            throw new CommonException("入库放款单不存在，id值为：{}", id);
        }
        return depotLoanGrant;
    }

    /**
     * 放款单二级审批
     *
     * @author xiang
     * @date 2023/09/14 09:44
     */
    @Transactional(rollbackFor = Exception.class)
    public void bankOpApproval(BankOpApprovalParam param) {
        //已确认-未通过
        if (BizStr.STATE_APPROVAL_G.equals(param.getBankOpApprovalState())) {
            DepotLoanGrant up = new DepotLoanGrant(param.getId(), BizStr.STATE_APPROVAL_G, param.getApprovalMsg(), BizStr.STATE_LOAN_GRANT_N
                    , param.getLoanPrice(), param.getLoanRatio(), param.getLoanAmount());
            up.setApprovalUser(authService.getLoginUser().getId());
            updateById(up);
            up = getById(param.getId());
            //放款申请同步入库记录
            depotWorkService.loanGrant(up.getLoanOrderNo(), null, BizStr.STATE_LOAN_GRANT_N);
        }
        //已上传凭证
        else if (BizStr.STATE_UPLOAD_Y.equals(param.getBankOpApprovalState())) {
            updateById(new DepotLoanGrant(param.getId(), param.getBankOpApprovalState()));
        } else if (BizStr.STATE_APPROVAL_Y.equals(param.getBankOpApprovalState())) {
            DepotLoanGrant info = this.queryEntity(param.getId());
            //放款同步入库记录
            depotWorkService.loanGrant(info.getLoanOrderNo(), null, BizStr.STATE_LOAN_GRANT_Y);
            //放款同步客户信息
            depotGrainInfoService.loanSync(info.getDepotId(), info.getGrainGroup(), info.getLoanAmount(), info.getOrderWeight());
            info.setBankOpApprovalState(BizStr.STATE_APPROVAL_Y);
            info.setLoanState(BizStr.STATE_LOAN_GRANT_Y);
            info.setApprovalTime(new Date());
            info.setApprovalMsg(param.getApprovalMsg() == null && info.getApprovalMsg() != null ? " " : param.getApprovalMsg());
            info.setApprovalUser(authService.getLoginUser().getId());
            updateById(info);
        }
    }

    /**
     * 检查贷款超额
     *
     * @param info    客户信息
     * @param loanSum 放款金额
     * @author xiang
     * @date 2023/09/14 15:00
     **/
    public void checkLoanExcess(DepotGrainInfo info, BigDecimal loanSum) {
        if (loanSum.compareTo(info.getLoanBalance()) < 1) {
            List<DepotLoanGrant> grants = lst(new DepotLoanGrant(info.getDepotId()));
            grants = grants.stream().filter(one -> "待审批/已确认/已上传凭证".contains(one.getBankOpApprovalState())).collect(Collectors.toList());
            BigDecimal loanOrderAmount = grants.stream().map(DepotLoanGrant::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (BigDecimalUtil.addVal(loanSum, loanOrderAmount).compareTo(info.getLoanBalance()) < 1)
                return;
        }
        throw new CommonException(String.format("%s 放款金额:%s；贷款余额:%s", BizExceptionEnum.ERROR12004.getMessage(), loanSum, info.getLoanBalance()));
    }

    /**
     * 检查贷款过期
     *
     * @param loanEndDate 到期日
     * @author xiang
     * @date 2023/09/14 15:00
     **/
    public void checkLoanOverDate(String loanEndDate) {
        if (DatesUtil.overTimeFlag(DatesUtil.forDate(loanEndDate)))
            throw new CommonException(BizExceptionEnum.ERROR12005.getMessage());
    }

    /**
     * 检查贷放款状态
     *
     * @param workIdLst 入库数据
     * @author xiang
     * @date 2023/09/14 15:00
     **/
    public void checkWorkIdLst(List<String> workIdLst) {
        List<DepotWork> works = depotWorkService.lst(workIdLst);
        List<String> licensePlates = new ArrayList<>();
        for (DepotWork work : works) {
            if (BizStr.STATE_LOAN_GRANT_Z.equals(work.getLoanState()) || BizStr.STATE_LOAN_GRANT_Y.equals(work.getLoanState()))
                licensePlates.add(work.getLicensePlate());
        }
        if (licensePlates.size() > 0)
            throw new CommonException(StringUtils.join(BizExceptionEnum.ERROR12008.getMessage(), ", 车辆:", Joiner.on(",").join(licensePlates)));
    }

}
