package cn.pluss.platform.deviceStock.impl;

import cn.pluss.platform.DeviceGoodsService;
import cn.pluss.platform.api.Result;
import cn.pluss.platform.api.ResultGenerator;
import cn.pluss.platform.device.DeviceOperateInfoService;
import cn.pluss.platform.device.DeviceTransferDetailService;
import cn.pluss.platform.device.DeviceTransferService;
import cn.pluss.platform.device.MercOrderNewService;
import cn.pluss.platform.deviceDetail.DeviceDetailService;
import cn.pluss.platform.deviceMerchantBuy.DeviceMerchantBuyService;
import cn.pluss.platform.deviceStock.DeviceStockService;
import cn.pluss.platform.dto.DeviceStockDTO;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.enums.DeviceOperateType;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.DeviceStockMapper;
import cn.pluss.platform.mapper.DeviceTypeMapper;
import cn.pluss.platform.merchant.MerchantCashPayCodeService;
import cn.pluss.platform.merchant.MerchantBaseInfoService;
import cn.pluss.platform.merchantDevice.MerchantDeviceService;
import cn.pluss.platform.userApp.UserAppService;
import cn.pluss.platform.util.DateUtils;
import cn.pluss.platform.util.StringUtil;
import cn.pluss.platform.vo.DeviceNumVO;
import cn.pluss.platform.vo.DeviceStockVO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
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 javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author bzg
 * @since 2020-11-11
 */
@Service
public class DeviceStockServiceImpl extends ServiceImpl<DeviceStockMapper, DeviceStock> implements DeviceStockService {

    @Setter(onMethod_ = {@Autowired})
    private UserAppService userAppService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantBaseInfoService merchantBaseInfoService;

    @Setter(onMethod_ = {@Autowired})
    private DeviceMerchantBuyService deviceMerchantBuyService;

    @Setter(onMethod_ = {@Autowired})
    private DeviceDetailService deviceDetailService;

    @Setter(onMethod_ = {@Autowired})
    private DeviceGoodsService deviceGoodsService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantDeviceService merchantDeviceService;

    @Autowired
    private MerchantCashPayCodeService cashPayCodeService;

    @Resource
    private DeviceTypeMapper deviceTypeMapper;

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private DeviceTransferService deviceTransferService;

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private DeviceTransferDetailService deviceTransferDetailService;

    @Resource
    private DeviceOperateInfoService deviceOperateInfoService;

    @Resource
    private MercOrderNewService mercOrderNewService;


    @Override
    public void bindPayCode(String payCode) {
        UserApp userApp = userAppService.queryUserAppByToken();
        bindPayCode(payCode, userApp);
    }

    @Override
    public void bindPayCode(String payCode, UserApp userApp) {
        MsgException.check(userApp == null, "当前登录用户信息为空！");

        DeviceStock deviceStock = new DeviceStock();
        deviceStock.setSnNo(payCode);
        deviceStock = getOne(new QueryWrapper<>(deviceStock));
        MsgException.check(deviceStock == null, "设备编号不存在！");


        MerchantBaseInfo info = new MerchantBaseInfo();
        info.setMerchantCode(userApp.getMerchantCode());
        MerchantBaseInfo baseInfo = merchantBaseInfoService.queryMerchantBaseInfo(info);
        MsgException.check(baseInfo == null, "当前商户异常或不存在！");

        MsgException.check("3".equals(deviceStock.getStatus()), "当前设备已绑定，请勿重复绑定！");

        deviceStock.setActMercName(baseInfo.getAlias());
        deviceStock.setActMercId(String.valueOf(baseInfo.getId()));
        deviceStock.setStatus("3");
        updateById(deviceStock);
        MerchantDevice merchantDevice = new MerchantDevice();
        if (StringUtils.isNotEmpty(deviceStock.getOrderNo())) {
            DeviceMerchantBuy buy = new DeviceMerchantBuy();
            buy.setOrderNo(deviceStock.getOrderNo());
            DeviceMerchantBuy buyInfo = deviceMerchantBuyService.queryDeviceMerchantBuy(buy);
            MsgException.check(buyInfo == null, "订单号不存在！");
            //已激活
            buyInfo.setActStatus("2");
            deviceMerchantBuyService.updateDeviceMerchantBuy(buyInfo);
            merchantDevice.setMerchantCode(baseInfo.getMerchantCode());
            merchantDevice.setMerchantName(baseInfo.getAlias());
            merchantDevice.setStatus(0);
            merchantDevice.setSn(payCode);
            merchantDevice.setCreateDt(new Date());
            merchantDevice.setUserId(userApp.getUserId());
            merchantDevice.setVenderCode(buyInfo.getVenderCode());
            merchantDevice.setVenderModel(buyInfo.getVenderModel());
            merchantDevice.setOrderNo(buyInfo.getOrderNo());
        } else {
            DeviceDetail deviceDetail = new DeviceDetail();
            deviceDetail.setCode(deviceStock.getCode());
            deviceDetail.setType(deviceStock.getType());
            deviceDetail = deviceDetailService.getOne(new QueryWrapper<>(deviceDetail));

            DeviceGoods deviceGoods = deviceGoodsService.getBySn(payCode);
            merchantDevice.setMerchantCode(baseInfo.getMerchantCode());
            merchantDevice.setMerchantName(baseInfo.getAlias());
            merchantDevice.setStatus(0);
            merchantDevice.setCreateDt(new Date());
            merchantDevice.setUserId(userApp.getUserId());
            merchantDevice.setSn(deviceStock.getSnNo());
            merchantDevice.setVenderModel(deviceDetail.getVenderModel());
            merchantDevice.setName(deviceGoods.getName());
            merchantDevice.setIntroDesc("NO." + deviceStock.getSnNo());
        }
        merchantDeviceService.save(merchantDevice);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbind(Long id) {
        if (id == null) {
            throw new MsgException("解绑出错");
        }

        LambdaUpdateWrapper<DeviceStock> uWrapper = Wrappers.lambdaUpdate();
        uWrapper.eq(DeviceStock::getId, id)
                .set(DeviceStock::getStatus, "2")
                .set(DeviceStock::getActMercId, null)
                .set(DeviceStock::getActMercName, null);
        update(uWrapper);

        DeviceStock device = getById(id);

        // 删除设备收银点关联的信息
        MerchantCashPayCode cashPayCode = cashPayCodeService.getByPayCode(device.getSnNo());
        if (cashPayCode != null) {
            cashPayCodeService.unbindPayCode(cashPayCode.getPayCode());
        }

        // 删除相关merchantDevice信息
        MerchantDevice merchantDevice = new MerchantDevice();
        merchantDevice.setSn(device.getSnNo());
        merchantDeviceService.remove(new QueryWrapper<>(merchantDevice));
    }

    @Override
    public DeviceStock getDevicebyNo(String deviceNo) {
        QueryWrapper<DeviceStock> queryWrapper = new QueryWrapper<DeviceStock>().eq("deviceNo", deviceNo);
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * 获取用户设备统计信息
     *
     * @param dto
     * @return
     */
    @Override
    public DeviceNumVO getStockTypeNumList(DeviceStockDTO dto) {
        UserApp userApp = userAppService.checkApiToken();
        dto.setUserId(String.valueOf(userApp.getUserId()));
        List<DeviceStockVO> list = baseMapper.getStockTypeNumList(dto);
        int totalDeviceNum = BigDecimal.ZERO.intValue();
        int totalBindNum = BigDecimal.ZERO.intValue();
        int totalUnBindNum = BigDecimal.ZERO.intValue();
        if (!list.isEmpty()) {
            for (DeviceStockVO o : list) {
                totalDeviceNum = totalDeviceNum + o.getTotalNum();
                totalBindNum = totalBindNum + o.getBindNum();
                totalUnBindNum = totalUnBindNum + o.getUnbindNum();
            }
        }
        DeviceNumVO countVo = new DeviceNumVO();
        countVo.setTotalDeviceNum(totalDeviceNum);
        countVo.setTotalBindNum(totalBindNum);
        countVo.setTotalUnbindNum(totalUnBindNum);
        countVo.setList(list);
        return countVo;
    }

    /**
     * 分页查询指定设备类型设备信息
     *
     * @param page
     * @param dto
     * @return
     */
    @Override
    public Page<DeviceStockVO> pageInfo(Page<DeviceStockVO> page, DeviceStockDTO dto) {
        return baseMapper.pageInfo(page, dto);
    }

    /**
     * 后台设备出库
     *
     * @param ids
     * @param accpetUserId
     * @param orderNo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<String> manageTransfer(List<Long> ids, Long accpetUserId, String orderNo) {
        List<DeviceStock> list = baseMapper.selectBatchIds(ids);
        MsgException.check(list.isEmpty(), "出库设备数据异常");
        UserApp userApp = userAppService.getUserAppByUserId(accpetUserId);
        MsgException.checkNull(userApp, "出库用户信息异常");
        MerchantBaseInfo merchant = null;
        if (StringUtils.isNotEmpty(orderNo)) {
            MercOrderNew mercOrder = mercOrderNewService.getOrderByNo(orderNo);
            MsgException.checkNull(mercOrder, "订单号输入有误！");
            MsgException.check(!MercOrderNew.STATUS_PAYED.equals(mercOrder.getStatus()), "订单不是已支付的订单");
            merchant = merchantBaseInfoService.getMerchantBaseInfoByUserId(mercOrder.getUserId().toString());
        }
        Set<String> codeList = new TreeSet<>();
        List<String> snNoList = new ArrayList<>(list.size());
        for (DeviceStock ds : list) {
            if ("01".equals(ds.getTransferStatus())) {
                MsgException.throwException("所选设备中包含待接收的设备，设备号为：" + ds.getSnNo());
            }
            codeList.add(ds.getCode());
            snNoList.add(ds.getSnNo());
        }
        List<String> codeShowFlagList = deviceTypeMapper.selectListCodeByShowFlag();
        boolean flag = false;
        String resCode = null;
        for (String code : codeList) {
            if (!codeShowFlagList.contains(code)) {
                flag = true;
                resCode = code;
            }
        }
        MsgException.check(flag, "所选设备中包含不能出库的设备类型，设备类型code为:" + resCode);
        UpdateWrapper<DeviceStock> updateWrapper = new UpdateWrapper<DeviceStock>().in("id", ids)
                .set("inStockTime", new Date()).set("belongUserId", userApp.getUserId()).set("extractUserId", userApp.getUserId());
        if (StringUtil.isNotEmpty(orderNo)) {
            updateWrapper.set("orderNo", orderNo);
            if (merchant != null) {
                updateWrapper.set("buyMercName", merchant.getAlias()).set("buyMercId", merchant.getId());
            }
        }
        update(updateWrapper);
        String batchNo = StringUtil.generateMixStr(3) + DateUtils.toString(DateUtils.currentDate(), "yyyyMMddHHmmss");
        DeviceTransfer transfer = new DeviceTransfer(null, userApp.getUserId(), batchNo, "01", DateUtils.currentDate(), "设备出库");
        deviceTransferService.save(transfer);
        List<DeviceTransferDetail> detailList = new ArrayList<>(list.size());
        for (String snNo : snNoList) {
            DeviceTransferDetail detail = new DeviceTransferDetail(transfer, snNo);
            detailList.add(detail);
        }
        deviceOperateInfoService.saveDeviceOperateListInfo(null, DeviceOperateType.IN, snNoList, "设备入库");
        deviceTransferDetailService.saveBatch(detailList);
        return ResultGenerator.genSuccessResult("出库成功", null);
    }

    /**
     * 获取设备详情
     *
     * @param dto
     * @return
     */
    @Override
    public DeviceStockVO detail(DeviceStockDTO dto) {
        MsgException.checkBlank(dto.getSnNo(), "缺失设备SN号");
        return baseMapper.detail(dto);
    }

    /**
     * 获取商户信息
     *
     * @param dto
     * @return
     */
    @Override
    public DeviceStockVO getMercInfo(DeviceStockDTO dto) {
        MsgException.checkBlank(dto.getSnNo(), "缺失设备SN号");
        DeviceStock stock = baseMapper.getDeviceBySnNo(dto.getSnNo());
        MsgException.checkNull(stock, "设备编号有误！");
        MsgException.check(!"3".equals(stock.getStatus()), "设备还未绑定，暂无商户信息！");
        return baseMapper.getMercInfo(dto);
    }

    @Override
    public Page<DeviceStockVO> pageMercDevice(Page<DeviceStockVO> page, Long userId, Long cashPlaceId) {
        return baseMapper.pageDeviceStock(page, userId, cashPlaceId);
    }

    @Override
    public Page<DeviceStockVO> apiPageMercDevice(Page<DeviceStockVO> page, Long cashPlaceId) {
        UserApp userApp = userAppService.queryUserAppByToken();
        return pageMercDevice(page, userApp.getUserId(), cashPlaceId);
    }

    /**
     * 绑定设备V2
     *
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void bindDevcieV2(DeviceStockDTO dto) {
        UserApp userApp = userAppService.checkApiToken();
        dto.setSnNo(dto.getQrNo());
        String snNo = dto.getSnNo();
        String deviceNo = dto.getDeviceNo();
        MsgException.check(StringUtil.isEmpty(snNo) && StringUtil.isEmpty(deviceNo), "设备编号和设备SN号至少需要填写一个");
        DeviceStock stock = null;
        if (StringUtil.isNotEmpty(snNo)) {
            snNo = snNo.replace("ALI_", "");
            stock = baseMapper.getDeviceBySnNo(snNo);
        } else {
            stock = baseMapper.getDeviceByDeviceNo(deviceNo);
        }
        MsgException.checkNull(stock, "设备号或SN号有误！");

        MerchantBaseInfo merchant = merchantBaseInfoService.getMerchantBaseInfoByUserId(userApp.getUserId().toString());
        // 被别人绑定的设备直接抛出异常
        if ("3".equals(stock.getStatus())) {
            if (Objects.equals(stock.getActMercId(), merchant.getId().toString())) {
                return;
            } else {
                throw new MsgException("该设备已被绑定，请勿重复绑定！");
            }
        }

        List<String> showFlag = deviceTypeMapper.selectListCodeByShowFlag();
        if(!showFlag.isEmpty() && showFlag.contains(stock.getCode())){
            boolean flag = userApp.getUserId().equals(stock.getBelongUserId());
            if (userApp.getParentId() != null) {
                boolean f1 = userApp.getParentId().equals(stock.getBelongUserId());
                flag = flag || f1;
                if(!flag){
                    UserApp parentApp = userAppService.getUserAppByUserId(userApp.getParentId());
                    if(parentApp != null && parentApp.getParentId() != null){
                        boolean f2 = parentApp.getParentId().equals(stock.getBelongUserId());
                        flag = flag || f2;
                    }
                }
            }
            MsgException.check(!flag, "绑定失败，当前设备不属于您或您的推广服务商团队，请联系客服或您的推广服务商处理！");
        }

        MsgException.checkNull(merchant, "当前商户还未认证成商户，暂时无法进行绑定操作");
        stock.setActMercName(merchant.getAlias());
        stock.setActMercId(String.valueOf(merchant.getId()));
        stock.setStatus("3");
        stock.setBindTime(DateUtils.currentDate());
        updateById(stock);
        DeviceOperateInfo operateInfo = new DeviceOperateInfo(userApp, DeviceOperateType.BIND.getCode(), stock.getSnNo(), null);
        deviceOperateInfoService.save(operateInfo);
    }

    @Override
    public DeviceStock checkBind(String sn) {
        MsgException.checkBlank(sn, "缺失设备SN号");
        DeviceStock deviceBySnNo = baseMapper.getDeviceBySnNo(sn);
        MsgException.checkBlank(deviceBySnNo.getActMercId(),"未绑定扫码pos");
        return deviceBySnNo;
    }

    @Override
    public <E extends IPage<DeviceStock>> E page(E page, Wrapper<DeviceStock> queryWrapper) {
        DeviceStock deviceStock = queryWrapper.getEntity();
        QueryWrapper<DeviceStock> qW = new QueryWrapper<>(deviceStock);
        if (StringUtil.isNotEmpty(deviceStock.getStartSnNo())) {
            qW.ge("snNo", deviceStock.getStartSnNo());
        }
        if (StringUtil.isNotEmpty(deviceStock.getEndSnNo())) {
            qW.le("snNo", deviceStock.getEndSnNo());
        }
        return super.page(page, qW);
    }
}
