package com.fjhx.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.BaseEntity;
import com.fjhx.constants.ErrorMsgConstant;
import com.fjhx.constants.LibrarySupplyLockConstant;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.ApplyPurchase;
import com.fjhx.entity.Order;
import com.fjhx.entity.OrderFlow;
import com.fjhx.enums.ApplyPurchaseStatusEnum;
import com.fjhx.enums.OrderStatusEnum;
import com.fjhx.mapper.ApplyPurchaseMapper;
import com.fjhx.service.ApplyPurchaseService;
import com.fjhx.service.OrderFlowService;
import com.fjhx.service.OrderService;
import com.fjhx.utils.Assert;
import org.springblade.core.redis.lock.RedisLockClient;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 申购单 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-08-25
 */
@Service
public class ApplyPurchaseServiceImpl extends ServiceImpl<ApplyPurchaseMapper, ApplyPurchase> implements ApplyPurchaseService {

    @Resource
    private RedisLockClient redisLockClient;

    @Autowired
    private OrderFlowService orderFlowService;

    @Autowired
    private OrderService orderService;

    @Override
    public void add(ApplyPurchase applyPurchase) {
        Assert.notEmpty(applyPurchase.getGoodsId(), "物品id不能为空");
        Assert.notEmpty(applyPurchase.getQuantity(), "申购数量不能为空");
        Assert.notEmpty(applyPurchase.getPlanArrivalTime(), "到货时间不能为空");

        // 到货数量
        applyPurchase.setArrivalQuantity(BigDecimal.ZERO);

        // 到货金额
        applyPurchase.setArrivalPrice(BigDecimal.ZERO);

        // 状态
        applyPurchase.setStatus(ApplyPurchaseStatusEnum.WAIT_START.getValue());

        // 申购单未完成
        applyPurchase.setCompleteStatus(StatusConstant.NO);

        save(applyPurchase);
    }

    @Override
    public void initiateSubscription(List<ApplyPurchase> applyPurchaseList, Long flowLinkNo, String code) {
        initiateSubscriptionFun(applyPurchaseList, flowLinkNo, () -> {
            Long count = count(Wrappers.<ApplyPurchase>lambdaQuery()
                    .eq(ApplyPurchase::getCode, code)
                    .eq(BaseEntity::getTenantId, AuthUtil.getTenantId()));
            Assert.eqZero(count, "申购单号已存在");
            return code;
        });
    }

    @Override
    public void initiateSubscriptionAuto(List<ApplyPurchase> applyPurchaseList, Long flowLinkNo, String codePrefix) {
        initiateSubscriptionFun(applyPurchaseList, flowLinkNo, () -> createApplyPurchaseCode(codePrefix));
    }

    @Override
    public void initiateSubscriptionAuto(List<ApplyPurchase> applyPurchaseList, Long flowLinkNo) {
        String codePrefix = "PA" + DateUtil.format(new Date(), "yyMMdd-");
        initiateSubscriptionAuto(applyPurchaseList, flowLinkNo, codePrefix);
    }

    @Override
    public void flowPass(Long flowLinkNo) {
        updateFlowStatus(flowLinkNo, ApplyPurchaseStatusEnum.PASS);
    }

    @Override
    public void flowNotPass(Long flowLinkNo) {
        updateFlowStatus(flowLinkNo, ApplyPurchaseStatusEnum.NOT_PASS);
    }

    @Override
    public void flowOrder(List<ApplyPurchase> applyPurchaseList, Long orderId, String orderCode, Long supplierId, Integer accountPeriod) {

        List<OrderFlow> orderFlowList = new ArrayList<>();

        for (ApplyPurchase applyPurchase : applyPurchaseList) {

            Long id = applyPurchase.getId();
            Assert.notEmpty(id, "申购单id不能为空");

            BigDecimal unitPrice = applyPurchase.getUnitPrice();
            Assert.notEmpty(unitPrice, "单价不能为空");

            applyPurchase.setVersion(null);
            applyPurchase.setOrderId(orderId);
            applyPurchase.setOrderCode(orderCode);
            applyPurchase.setSupplierId(supplierId);
            applyPurchase.setAccountPeriod(accountPeriod);
            applyPurchase.setStatus(ApplyPurchaseStatusEnum.PURCHASE_FLOW.getValue());

            // 申购金额
            applyPurchase.setApplyPrice(unitPrice.multiply(applyPurchase.getQuantity()));

            OrderFlow orderFlow = new OrderFlow();
            orderFlow.setOrderId(orderId);
            orderFlow.setApplyPurchaseId(id);
            orderFlow.setUnitPrice(applyPurchase.getUnitPrice());
            orderFlow.setRemark(applyPurchase.getRemark());
            orderFlowList.add(orderFlow);
        }

        // 保留订单采购记录
        orderFlowService.saveBatch(orderFlowList);

        updateBatchById(applyPurchaseList);

    }

    @Override
    public void flowOrderPass(Long orderId) {
        update(Wrappers.<ApplyPurchase>lambdaUpdate()
                .eq(ApplyPurchase::getOrderId, orderId)
                .set(ApplyPurchase::getStatus, ApplyPurchaseStatusEnum.PURCHASED.getValue())
                .set(BaseEntity::getUpdateTime, new Date())
                .set(BaseEntity::getUpdateUser, AuthUtil.getUserId())
        );
    }

    @Override
    public void flowOrderNotPass(Long orderId) {
        update(Wrappers.<ApplyPurchase>lambdaUpdate()
                .eq(ApplyPurchase::getOrderId, orderId)
                .set(ApplyPurchase::getStatus, ApplyPurchaseStatusEnum.PASS.getValue())
                .set(ApplyPurchase::getOrderId, null)
                .set(ApplyPurchase::getOrderCode, null)
                .set(ApplyPurchase::getSupplierId, null)
                .set(ApplyPurchase::getAccountPeriod, null)
                .set(ApplyPurchase::getApplyPrice, null)
                .set(ApplyPurchase::getUnitPrice, null)
                .set(ApplyPurchase::getRemark, null)
                .set(BaseEntity::getUpdateTime, new Date())
                .set(BaseEntity::getUpdateUser, AuthUtil.getUserId())
        );
    }

    @Override
    public void arrival(Long applyPurchaseId, BigDecimal arrivalQuantity, Boolean autoComplete) {

        ApplyPurchase applyPurchase = getById(applyPurchaseId);
        Assert.notEmpty(applyPurchase, "申购单号为空");

        // 添加到货数量
        BigDecimal totalArrivalQuantity = applyPurchase.getArrivalQuantity().add(arrivalQuantity);
        applyPurchase.setArrivalQuantity(totalArrivalQuantity);

        // 赋值到货金额
        applyPurchase.setArrivalPrice(totalArrivalQuantity.multiply(applyPurchase.getUnitPrice()));

        // 是否全部到货
        BigDecimal quantity = applyPurchase.getQuantity();
        if (totalArrivalQuantity.compareTo(quantity) >= 0) {
            applyPurchase.setStatus(ApplyPurchaseStatusEnum.ARRIVAL.getValue());
            if (autoComplete) {
                applyPurchase.setCompleteStatus(StatusConstant.YES);
            }
        } else {
            applyPurchase.setStatus(ApplyPurchaseStatusEnum.PART_ARRIVAL.getValue());
        }

        Assert.eqTrue(updateById(applyPurchase), ErrorMsgConstant.SYSTEM_BUSY_ERROR);

        // 赋值订单到货金额
        Long orderId = applyPurchase.getOrderId();
        Order order = orderService.getById(orderId);
        order.setArrivalPrice(order.getArrivalPrice().add(arrivalQuantity.multiply(applyPurchase.getUnitPrice())));

        // 如果完成订单，修改订单状态为已完成
        if (autoComplete && totalArrivalQuantity.compareTo(quantity) >= 0 && orderIsComplete(orderId)) {
            order.setStatus(OrderStatusEnum.COMPLETED.getValue());
        }

        Assert.eqTrue(orderService.updateById(order), ErrorMsgConstant.SYSTEM_BUSY_ERROR);
    }

    @Override
    public void endApplyPurchase(Long applyPurchaseId) {
        update(Wrappers.<ApplyPurchase>lambdaUpdate()
                .eq(ApplyPurchase::getId, applyPurchaseId)
                .set(BaseEntity::getUpdateTime, new Date())
                .set(BaseEntity::getUpdateUser, AuthUtil.getUserId())
                .set(ApplyPurchase::getCompleteStatus, StatusConstant.YES));
    }

    @Override
    public void discardApplyPurchase(Long applyPurchaseId) {
        update(Wrappers.<ApplyPurchase>lambdaUpdate()
                .eq(ApplyPurchase::getId, applyPurchaseId)
                .set(BaseEntity::getUpdateTime, new Date())
                .set(BaseEntity::getUpdateUser, AuthUtil.getUserId())
                .set(ApplyPurchase::getStatus, ApplyPurchaseStatusEnum.DISCARD.getValue())
        );
    }

    @Override
    public boolean orderIsComplete(Long orderId) {

        Long count = count(Wrappers.<ApplyPurchase>lambdaQuery()
                .eq(ApplyPurchase::getOrderId, orderId)
                .eq(ApplyPurchase::getCompleteStatus, StatusConstant.NO)
        );

        return count == 0;
    }

    /**
     * 发起申购
     *
     * @param applyPurchaseList 申购列表
     * @param flowLinkNo        流程关联编号
     * @param fun               获取申购单号方法
     */
    private void initiateSubscriptionFun(List<ApplyPurchase> applyPurchaseList, Long flowLinkNo, java.util.function.Supplier<String> fun) {

        String tenantId = AuthUtil.getTenantId();

        Boolean flag = redisLockClient.lockFair(LibrarySupplyLockConstant.APPLY_PURCHASE_CODE_LOCK + tenantId,
                () -> {

                    String code = fun.get();

                    applyPurchaseList.forEach(applyPurchase -> {
                        // 赋值申购单号
                        applyPurchase.setCode(code);
                        // 状态改为审批中
                        applyPurchase.setStatus(ApplyPurchaseStatusEnum.IN_APPROVAL.getValue());
                        // 赋值流程id
                        applyPurchase.setFlowLinkNo(flowLinkNo);
                    });
                    updateBatchById(applyPurchaseList);

                    return true;
                });

        Assert.eqTrue(flag, ErrorMsgConstant.SYSTEM_BUSY_ERROR);
    }

    /**
     * 自动生成申购单编号
     */
    public String createApplyPurchaseCode(String codePrefix) {
        StringBuilder builder = new StringBuilder();
        builder.append(codePrefix);

        ApplyPurchase applyPurchase = getOne(Wrappers.<ApplyPurchase>lambdaQuery()
                .select(ApplyPurchase::getCode)
                .eq(BaseEntity::getTenantId, AuthUtil.getTenantId())
                .likeRight(ApplyPurchase::getCode, codePrefix)
                .orderByDesc(ApplyPurchase::getCode)
                .last("limit 1")
        );

        if (applyPurchase == null) {
            return builder.append("001").toString();
        }

        int codeNum = Integer.parseInt(applyPurchase.getCode().replace(codePrefix, ""));

        return builder.append(codeNum < 9 ? "00" : codeNum < 99 ? "0" : "").append(codeNum + 1).toString();
    }

    /**
     * 修改申购单状态
     */
    private void updateFlowStatus(Long flowLinkNo, ApplyPurchaseStatusEnum applyPurchaseStatusEnum) {
        update(Wrappers.<ApplyPurchase>lambdaUpdate()
                .eq(ApplyPurchase::getFlowLinkNo, flowLinkNo)
                .set(BaseEntity::getUpdateTime, new Date())
                .set(BaseEntity::getUpdateUser, AuthUtil.getUserId())
                .set(ApplyPurchase::getStatus, applyPurchaseStatusEnum.getValue()));
    }

}
