package com.qmth.sop.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
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.qmth.sop.business.bean.dto.DataPermissionDto;
import com.qmth.sop.business.bean.dto.SopCrmInfo;
import com.qmth.sop.business.bean.params.DeviceInOutForm;
import com.qmth.sop.business.bean.params.DeviceInOutSubmitParam;
import com.qmth.sop.business.bean.result.DeviceInOutResult;
import com.qmth.sop.business.entity.*;
import com.qmth.sop.business.mapper.TBDeviceInOutMapper;
import com.qmth.sop.business.service.*;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.*;
import com.qmth.sop.common.util.ServletUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 设备出入库登记 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2023-08-01
 */
@Service
public class TBDeviceInOutServiceImpl extends ServiceImpl<TBDeviceInOutMapper, TBDeviceInOut> implements TBDeviceInOutService {

    @Resource
    private SysDeviceService sysDeviceService;

    @Resource
    private SequenceService sequenceService;

    @Resource
    private SysUserService sysUserService;

    @Resource
    private TBCrmService tbCrmService;

    @Resource
    private SysCustomService sysCustomService;

    @Resource
    private TBDeviceDeliveryService tbDeviceDeliveryService;

    @Override
    public IPage<DeviceInOutResult> findDeviceInOutPageBySop(Long serviceUnitId, DeviceUsageTypeEnum usageType, Long userId, DeviceStatusEnum deviceStatus, Long inOutTimeStart, Long inOutTimeEnd, String deviceNo,
            String deviceSerialNo, String customName, String location, String address, String serialNo, Integer pageNumber, Integer pageSize) {
        deviceNo = SystemConstant.translateSpecificSign(deviceNo);
        deviceSerialNo = SystemConstant.translateSpecificSign(deviceSerialNo);
        customName = SystemConstant.translateSpecificSign(customName);
        location = SystemConstant.translateSpecificSign(location);
        address = SystemConstant.translateSpecificSign(address);
        serialNo = SystemConstant.translateSpecificSign(serialNo);

        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionDto dpr = sysUserService.buildUserDataPermission(requestUser.getId());
        IPage<DeviceInOutResult> result = this.baseMapper.findDeviceInOutPageBySop(new Page<>(pageNumber, pageSize),
                serviceUnitId, usageType, userId, deviceStatus, inOutTimeStart, inOutTimeEnd, deviceNo, deviceSerialNo,
                customName, location, address, serialNo, dpr);
        result.getRecords().forEach(e -> {
            String addressArrTemp = e.getAddressArrTemp();
            String locationArrTemp = e.getLocationArrTemp();
            if (addressArrTemp != null && addressArrTemp.length() > 0) {
                e.setAddressArr(JSON.parseArray(addressArrTemp, String.class));
            }
            if (locationArrTemp != null && locationArrTemp.length() > 0) {
                e.setLocationArr(JSON.parseArray(locationArrTemp, String.class));
            }
        });

        return result;
    }

    @Override
    public List<DeviceInOutResult> findDeviceCanOutInfo(Long supplierId, String sopNo) {
        String crmNo = null;
        if (sopNo != null && sopNo.length() > 0) {
            SopCrmInfo sopCrmInfo = tbCrmService.findSopCrmInfoBySop(sopNo);
            crmNo = sopCrmInfo.getCrmNo();
        }

        List<TBDeviceDelivery> tbDeviceDeliveryList = tbDeviceDeliveryService.list(
                new QueryWrapper<TBDeviceDelivery>().lambda().eq(TBDeviceDelivery::getEffect, true));

        List<DeviceInOutResult> result = new ArrayList<>();
        List<DeviceInOutResult> deviceInOutResultList = this.baseMapper.findDeviceCanOutInfo(supplierId,
                DeviceStatusEnum.NORMAL, InOutTypeEnum.IN);
        for (DeviceInOutResult e : deviceInOutResultList) {
            String locationArrTemp = e.getLocationArrTemp();
            if (locationArrTemp != null && locationArrTemp.length() > 0) {
                e.setLocationArr(JSON.parseArray(locationArrTemp, String.class));
            }
            String serialNo = e.getSerialNo();
            List<TBDeviceDelivery> cellDeliveryList = tbDeviceDeliveryList.stream().filter(dd -> dd.getSerialNo().equals(serialNo)).collect(Collectors.toList());

            if (CollectionUtils.isEmpty(cellDeliveryList)) {
                result.add(e);
            } else {
                if (cellDeliveryList.size() > 1) {
                    throw ExceptionResultEnum.ERROR.exception(String.format("设备发货信息，设备[%s]存在多条有效的记录", serialNo));
                }
                TBDeviceDelivery tbDeviceDelivery = cellDeliveryList.get(0);
                String deliveryCrmNo = tbDeviceDelivery.getCrmNo();
                if (!InOutTypeEnum.OUT.equals(tbDeviceDelivery.getDeliveryType()) || !DeviceDeliveryStatusEnum.DELIVER.equals(tbDeviceDelivery.getStatus())) {
                    // 出库 且 已发货的可以出库
                    continue;
                }
                if (crmNo != null && crmNo.length() > 0) {
                    // 用于sop（若设备发货管理里有数据，只能选用派单号相同的）
                    if (crmNo.equals(deliveryCrmNo)) {
                        e.setDefaultData(true);
                        e.setExpressNo(tbDeviceDelivery.getExpressNo());
                        result.add(e);
                    }
                } else {
                    // 用于培训
                    if (deliveryCrmNo == null || deliveryCrmNo.length() == 0) {
                        result.add(e);
                    }
                }
            }
        }
        return result;
    }

    @Override
    public List<DeviceInOutResult> findDeviceCanInInfo(Long supplierId, String sopNo) {
        return this.baseMapper.findDeviceCanInInfo(supplierId, InOutTypeEnum.OUT, sopNo).stream().peek(e -> {
            String locationArrTemp = e.getLocationArrTemp();
            if (locationArrTemp != null && locationArrTemp.length() > 0) {
                e.setLocationArr(JSON.parseArray(locationArrTemp, String.class));
            }
            e.setDefaultData(true);
        }).collect(Collectors.toList());
    }

    @Transactional
    @Override
    public void deviceInOutSubmit(DeviceInOutSubmitParam deviceInOutSubmitParam) {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();

        Long inOutTime = deviceInOutSubmitParam.getInOutTime();
        InOutTypeEnum inOutType = deviceInOutSubmitParam.getInOutType();

        Long serviceUnitId = deviceInOutSubmitParam.getServiceUnitId();
        String crmNo = deviceInOutSubmitParam.getCrmNo();
        String sopNo = deviceInOutSubmitParam.getSopNo();

        // 设备出库时因为可以sop编辑的原因，去掉重复出库的
        List<TBDeviceInOut> alreadyOutList = new ArrayList<>();
        if (InOutTypeEnum.OUT.equals(inOutType)) {
            alreadyOutList = this.list(new QueryWrapper<TBDeviceInOut>().lambda().eq(TBDeviceInOut::getSopNo, sopNo)
                    .eq(TBDeviceInOut::getType, InOutTypeEnum.OUT));
        }
        List<String> alreadyOutSerialNoList = alreadyOutList.stream().map(TBDeviceInOut::getDeviceSerialNo).distinct().collect(Collectors.toList());

        String customName = null;
        if (crmNo != null && crmNo.length() > 0) {
            TBCrm tbCrm = tbCrmService.findByCrmNo(crmNo);
            if (Objects.nonNull(tbCrm)) {
                Long customId = tbCrm.getCustomId();
                SysCustom sysCustom = sysCustomService.getById(customId);
                if (Objects.nonNull(sysCustom)) {
                    customName = sysCustom.getName();
                }
            }
        }

        DeviceUsageTypeEnum usageType;
        if (sopNo != null && sopNo.length() > 0) {
            usageType = DeviceUsageTypeEnum.PROJECT;
        } else {
            usageType = DeviceUsageTypeEnum.OTHER;
        }
        if (deviceInOutSubmitParam.getDeviceInOutFormList().size() > deviceInOutSubmitParam.getDeviceInOutFormList().stream().map(DeviceInOutForm::getSerialNo).distinct().count()) {
            throw ExceptionResultEnum.ERROR.exception("出入库登记表中设备编号有重复");
        }

        List<DeviceInOutForm> deviceInOutFormList = deviceInOutSubmitParam.getDeviceInOutFormList();
        String finalCustomName = customName;
        List<TBDeviceInOut> tbDeviceInOutList = deviceInOutFormList.stream().filter(e -> !alreadyOutSerialNoList.contains(e.getSerialNo())).flatMap(e -> {
            TBDeviceInOut tbDeviceInOut = new TBDeviceInOut();
            if (serviceUnitId != null && serviceUnitId > 0) {
                tbDeviceInOut.setServiceId(serviceUnitId);
            }
            if (crmNo != null && crmNo.length() > 0) {
                tbDeviceInOut.setCrmNo(crmNo);
            }
            if (sopNo != null && sopNo.length() > 0) {
                tbDeviceInOut.setSopNo(sopNo);
            }
            try {
                tbDeviceInOut.setSerialNo(sequenceService.createSerialNo(SequenceEnum.DEVICE_IN_OUT_CODE));
            } catch (InterruptedException ex) {
                throw ExceptionResultEnum.ERROR.exception("流水号生成失败");
            }
            tbDeviceInOut.setUserId(requestUser.getId());
            tbDeviceInOut.setType(inOutType);
            tbDeviceInOut.setDeviceSerialNo(e.getSerialNo());
            tbDeviceInOut.setSupplierName(e.getSupplierName());
            tbDeviceInOut.setLocation(e.getLocation());
            tbDeviceInOut.setAddress(e.getAddress());
            tbDeviceInOut.setAddressArr(JSON.toJSONString(e.getAddressArr()));
            tbDeviceInOut.setStatus(e.getDeviceStatus());
            tbDeviceInOut.setUsageType(usageType);
            tbDeviceInOut.setBasePhotoPath(e.getBasePhotoPath());
            tbDeviceInOut.setInOutTime(inOutTime);
            if (finalCustomName != null && finalCustomName.length() > 0) {
                tbDeviceInOut.setCustomName(finalCustomName);
            }

            UpdateWrapper<SysDevice> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(SysDevice::getLocation, e.getAddress())
                    .set(SysDevice::getLocationArr, JSON.toJSONString(e.getAddressArr()))
                    .set(SysDevice::getScanCount, e.getScanCount())
                    .set(SysDevice::getStatus, e.getDeviceStatus()).set(SysDevice::getBound, inOutType).eq(SysDevice::getSerialNo, e.getSerialNo());
            sysDeviceService.update(updateWrapper);

            return Stream.of(tbDeviceInOut);
        }).collect(Collectors.toList());
        this.saveBatch(tbDeviceInOutList);
        // 更新发货出库记录（快递单）
        if (InOutTypeEnum.OUT.equals(inOutType) && deviceInOutSubmitParam.getPushSupplier()) {
            tbDeviceDeliveryService.updateOutRecord(deviceInOutFormList);
        }

        // 新增发货入库记录
        if (InOutTypeEnum.IN.equals(inOutType) && deviceInOutSubmitParam.getPushSupplier()) {
            tbDeviceDeliveryService.addInRecord(deviceInOutFormList);
        }
    }

    @Override
    public IPage<DeviceInOutResult> findDeviceInOutPageBySource(Long serviceUnitId, DeviceUsageTypeEnum usageType, Long userId, DeviceStatusEnum deviceStatus, Long inOutTimeStart, Long inOutTimeEnd, String deviceNo,
            String deviceSerialNo, String customName, String location, String address, String serialNo, Integer pageNumber, Integer pageSize) {
        deviceNo = SystemConstant.translateSpecificSign(deviceNo);
        customName = SystemConstant.translateSpecificSign(customName);
        location = SystemConstant.translateSpecificSign(location);
        address = SystemConstant.translateSpecificSign(address);
        serialNo = SystemConstant.translateSpecificSign(serialNo);
        deviceSerialNo = SystemConstant.translateSpecificSign(deviceSerialNo);

        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionDto dpr = sysUserService.buildUserDataPermission(requestUser.getId());

        IPage<DeviceInOutResult> result = this.baseMapper.findDeviceInOutPageBySource(new Page<>(pageNumber, pageSize),
                serviceUnitId, usageType, userId, deviceStatus, inOutTimeStart, inOutTimeEnd, deviceNo, deviceSerialNo,
                customName, location, address, serialNo, dpr);

        result.getRecords().forEach(e -> {
            String addressArrTemp = e.getAddressArrTemp();
            String locationArrTemp = e.getLocationArrTemp();
            if (addressArrTemp != null && addressArrTemp.length() > 0) {
                e.setAddressArr(JSON.parseArray(addressArrTemp, String.class));
            }
            if (locationArrTemp != null && locationArrTemp.length() > 0) {
                e.setLocationArr(JSON.parseArray(locationArrTemp, String.class));
            }
        });
        return result;
    }
}