package com.fjhx.service.water.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.water.Water;
import com.fjhx.entity.water.WaterTag;
import com.fjhx.enums.DeviceTypeEnum;
import com.fjhx.enums.InTypeEnum;
import com.fjhx.enums.OutTypeEnum;
import com.fjhx.mapper.water.WaterMapper;
import com.fjhx.params.water.WaterVo;
import com.fjhx.service.contract.ContractDetailsService;
import com.fjhx.service.contract.ContractService;
import com.fjhx.service.flow.ReturnOrScrapIssueFlowService;
import com.fjhx.service.quality.QualityTestingService;
import com.fjhx.service.stock.StockService;
import com.fjhx.service.water.WaterDetailService;
import com.fjhx.service.water.WaterService;
import com.fjhx.service.water.WaterTagService;
import com.fjhx.utils.Assert;
import org.springblade.core.log.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 流水表 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-09-20
 */
@Service
public class WaterServiceImpl extends ServiceImpl<WaterMapper, Water> implements WaterService {

    private static final Object ADD_OBJ = new Object();

    @Autowired
    private WaterDetailService waterDetailService;

    @Autowired
    private WaterTagService waterTagService;

    @Autowired
    private StockService stockService;

    @Autowired
    private ContractDetailsService contractDetailsService;

    @Autowired
    private QualityTestingService qualityTestingService;

    @Autowired
    @Lazy
    private ReturnOrScrapIssueFlowService returnOrScrapIssueFlowService;

    @Autowired
    private ContractService contractService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(WaterVo waterVo) {

        // 必填字段校验
        requiredFieldVerification(waterVo);

        // 出库或入库类型枚举
        Enum<?> typeEnum = getInOutType(waterVo.getType());

        // 如果是退货或者报废,审批通过后再出库
        if (typeEnum instanceof OutTypeEnum
                && (typeEnum.equals(OutTypeEnum.RETURN_ISSUE) || typeEnum.equals(OutTypeEnum.SCRAP_ISSUE))
                && !StatusConstant.YES.equals(waterVo.getFlowFlag())) {
            waterVo.setId(IdWorker.getId());
            waterVo.setFlowFlag(StatusConstant.YES);
            returnOrScrapIssueFlowService.create(waterVo);
            return;
        }

        // 获取变更标签
        List<WaterTag> waterTagList = getWaterTagList(waterVo.getWaterTagIdList());

        // 判断出库是否异常
        setErrorOutStatus(typeEnum, waterVo);

        // 添加流水
        save(waterVo);

        // 添加流水明细
        waterDetailService.add(waterVo, waterTagList);


        synchronized (ADD_OBJ) {

            // 更新库存
            stockService.edit(typeEnum, waterTagList);

            // 修改标签在库信息
            waterTagService.editInHouse(typeEnum, waterTagList, waterVo.getStockHouseId());

            // 如果是入库
            if (typeEnum instanceof InTypeEnum) {

                // 如果标签不是本场入库状态，则更新合同到货数量和在途数量
                contractDetailsService.updateAfloatAndArrivalQuantity(waterTagList);

                // 生成质检单
                qualityTestingService.create(waterTagList);

            } else if (typeEnum.equals(OutTypeEnum.RETURN_ISSUE)) {

                // 退货出库新增合同明细退货数量与合同退货金额
                contractService.updateBackAmountAndQuantity(waterTagList);

            }

        }

    }

    /**
     * 必填字段校验
     */
    private void requiredFieldVerification(WaterVo waterVo) {
        // Assert.notEmpty(waterVo.getStockHouseId(), "仓库id不能为空");
        Assert.notEmpty(waterVo.getOperUserId(), "操作人id不能为空");
        Assert.notEmpty(waterVo.getType(), "库存变更类型不能为空");
        Assert.notEmpty(waterVo.getDevice(), "出入库设备类型不能为空");
        Assert.notEmpty(waterVo.getWaterTagIdList(), "标签id数组不能为空");
    }

    /**
     * 获取出入库类型
     */
    private Enum<?> getInOutType(Integer type) {
        // 判断是否是入库类型
        InTypeEnum inTypeEnum = InTypeEnum.get(type);
        if (inTypeEnum != null) {
            return inTypeEnum;
        }
        // 判断是否是出库类型
        OutTypeEnum outTypeEnum = OutTypeEnum.get(type);
        if (outTypeEnum != null) {
            return outTypeEnum;
        }

        throw new ServiceException("未知出入库类型");
    }

    /**
     * 获取变更标签
     */
    private List<WaterTag> getWaterTagList(List<Long> waterTagIdList) {
        List<WaterTag> waterTagList = waterTagService.listByIds(waterTagIdList);
        Assert.eqTrue(waterTagIdList.size() != waterTagList.size(), "存在未知标签id");
        return waterTagList;
    }

    /**
     * TODO 一体机出库时，判断是否异常出库
     *
     * @param waterVo
     */
    private void setErrorOutStatus(Enum<?> typeEnum, WaterVo waterVo) {
        if (typeEnum instanceof InTypeEnum || !DeviceTypeEnum.HANDHELD_MACHINE.getType().equals(waterVo.getDevice())) {
            waterVo.setErrorOutStatus(StatusConstant.NO);
            return;
        }

        waterVo.setErrorOutStatus(StatusConstant.NO);
    }

}
