package cn.pluss.platform.merchant.impl;

import cn.jiguang.common.utils.StringUtils;
import cn.pluss.platform.converter.Converter;
import cn.pluss.platform.converter.MerchantCashPlaceConverter;
import cn.pluss.platform.deviceStock.DeviceStockService;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.MerchantCashPayCodeMapper;
import cn.pluss.platform.mapper.MerchantCashPlaceMapper;
import cn.pluss.platform.mapper.MerchantCashPlaceStaffMapper;
import cn.pluss.platform.mapper.UserAppMapper;
import cn.pluss.platform.merchant.MerchantCashPayCodeService;
import cn.pluss.platform.merchant.MerchantCashPlaceService;
import cn.pluss.platform.merchant.MerchantCashPlaceStaffService;
import cn.pluss.platform.merchant.MerchantBaseInfoService;
import cn.pluss.platform.merchantChannelStatus.MerchantChannelStatusService;
import cn.pluss.platform.userApp.UserAppService;
import cn.pluss.platform.util.StringUtil;
import cn.pluss.platform.vo.MerchantCashPlaceStaffVO;
import cn.pluss.platform.vo.MerchantCashPlaceVO;
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 lombok.Setter;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 商户收银点表 服务实现类
 * </p>
 *
 * @author Djh
 * @since 2021-03-23
 */
@Service
public class MerchantCashPlaceServiceImpl extends ServiceImpl<MerchantCashPlaceMapper, MerchantCashPlace> implements MerchantCashPlaceService {

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

    @Setter(onMethod_ = {@Autowired})
    private MerchantChannelStatusService channelStatusService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantCashPlaceStaffService cashPlaceStaffService;

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

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private MerchantCashPayCodeService cashPayCodeService;

    @Setter(onMethod_ = {@Autowired})
    private DeviceStockService deviceStockService;

    @Setter(onMethod_ = {@Autowired})
    private MerchantCashPayCodeMapper merchantCashPayCodeMapper;

    @Setter(onMethod_ = {@Autowired})
    private MerchantCashPlaceStaffMapper merchantCashPlaceStaffMapper;

    @Setter(onMethod_ = {@Autowired})
    private UserAppMapper userAppMapper;


    @Override
    public boolean saveOrUpdate(MerchantCashPlace entity) {

        if (entity.getUserId() == null) {
            throw new MsgException("缺少用户id");
        }

        UserApp userApp = new UserApp().setUserId(entity.getUserId());

        MerchantBaseInfo mbi = merchantBaseInfoService.getMerchantBaseInfoByUserId(userApp.getUserId() + "");

        checkAvailable(userApp.getUserId() + "", entity.getUserId() + "");

        if (mbi.getMerchantCode() == null) {
            throw new MsgException("请先完成商户进件");
        }

        // MerchantChannelStatus channelStatus = channelStatusService.getValidData(mbi.getMerchantCode());
        // if (channelStatus == null) {
        //     throw new MsgException("请先完成商户进件");
        // }
        //
        // if (!MerchantChannelStatus.isAudited(channelStatus)) {
        //     throw new MsgException("请先完成商户进件");
        // }

        if (StringUtils.isEmpty(entity.getName())) {
            throw new MsgException("缺少收银台名称");
        }

        if (StringUtils.isNotEmpty(entity.getCode())) {
            MerchantCashPlace existData = new MerchantCashPlace()
                    .setCode(entity.getCode());
            existData = getOne(new QueryWrapper<>(existData));

            if (existData == null) {
                throw new MsgException("收银台编号不存在或编号对应的商户不存在");
            } else {
                MerchantCashPayCode cashPayCode = new MerchantCashPayCode();
                cashPayCode.setCashPlaceId(existData.getId());
                cashPayCode = cashPayCodeService.getOne(new QueryWrapper<>(cashPayCode));
                boolean flag = cashPayCode != null && cashPayCode.getPayCode().equals(userApp.getUserId() + "") && !entity.getUserId().equals(userApp.getUserId());
                if (flag) {
                    throw new MsgException("默认收银点无法修改归属商户");
                }

                entity.setId(existData.getId());
            }
        } else {
            MerchantCashPlace existData = getOne(new QueryWrapper<>(entity));
            if (existData != null) {
                throw new MsgException("收银台名称不能重复");
            }

            String code;
            while (true) {
                code = StringUtil.genRandomNum(7);
                MerchantCashPlace existData2 = new MerchantCashPlace().setCode(code);
                existData2 = getOne(new QueryWrapper<>(existData2));
                if (existData2 == null) {
                    break;
                }
            }
            entity.setCode(code);
        }


        entity.setBindingCode(mbi.getBindingCode());

        // 查看对应的收银台是否已经存在
        MerchantCashPlace existData = new MerchantCashPlace();
        existData.setUserId(entity.getUserId());
        existData.setName(entity.getName());

        existData = getOne(new QueryWrapper<>(existData));
        if (existData != null && !existData.getId().equals(entity.getId())) {
            throw new MsgException("该收银点已存在");
        }

        return super.saveOrUpdate(entity);
    }

    /**
     * 判断userId的多商户列表中是否包含selectUserId
     * @param userId        用户id
     * @param selectUserId  多商户列表校验用户id
     */
    private void checkAvailable(String userId, String selectUserId) {
        if (userId.equals(selectUserId)) {
            return;
        }

        List<MerchantBaseInfo> mbiList = merchantBaseInfoService.getAllByUserId(userId);
        boolean flag = false;
        for (MerchantBaseInfo merchantBaseInfo : mbiList) {
            if (selectUserId.equals(merchantBaseInfo.getUserId())) {
                flag = true;
                break;
            }
        }

        if (!flag) {
            throw new MsgException("拒绝访问");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void createDefaultCashPlace(Long userId) {
        // 新建收银点
        MerchantCashPlace cashPlace = new MerchantCashPlace();
        cashPlace.setName("收银点一");
        cashPlace.setUserId(userId);
        MerchantCashPlace existData = getOne(new QueryWrapper<>(cashPlace));
        if (existData != null) {
            // 如果初始的收银点已存在
            return;
        }

        saveOrUpdate(cashPlace);

        // 绑定线上码
        MerchantCashPayCode cashPayCode = new MerchantCashPayCode();
        cashPayCode.setCashPlaceId(cashPlace.getId());
        cashPayCode.setPayCode(userId.toString());
        cashPayCodeService.save(cashPayCode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delByCodeForApp(String code) {
        UserApp userApp = userAppService.queryUserAppByToken();
        MerchantBaseInfo mbi = merchantBaseInfoService.getMerchantBaseInfoByUserId(userApp.getUserId() + "");

        MerchantCashPlace cashPlace = new MerchantCashPlace().setCode(code);
        cashPlace = getOne(new QueryWrapper<>(cashPlace));
        if (cashPlace == null) {
            throw new MsgException("该收银台不存在");
        }

        if (!Objects.equals(mbi.getUserId(), cashPlace.getUserId() + "") && !Objects.equals(mbi.getBindingCode(), cashPlace.getBindingCode())) {
            throw new MsgException("拒绝访问");
        }

        MerchantCashPayCode cashPayCode = new MerchantCashPayCode();
        cashPayCode.setCashPlaceId(cashPlace.getId());
        cashPayCode = cashPayCodeService.getOne(new QueryWrapper<>(cashPayCode));
        if (cashPayCode != null && cashPayCode.getPayCode().equals(userApp.getUserId() + "")) {
            throw new MsgException("默认收银点不能删除");
        }

        cashPlace.setCode(code);
        removeById(cashPlace.getId());

        // 同时删除绑定的码牌关系记录

        if (cashPayCode != null) {
            cashPayCodeService.removeById(cashPayCode.getCashPlaceId());
        }
    }

    @Override
    public List<MerchantCashPlaceVO> getListForApp(Page<MerchantCashPlace> page, MerchantCashPlace merchantCashPlace) {
        UserApp userApp = userAppService.queryUserAppByToken();
        QueryWrapper<MerchantCashPlace> qW = new QueryWrapper<>();
        qW.orderByDesc("createTime");

        List<MerchantBaseInfo> all = merchantBaseInfoService.getAllByUserId(userApp.getUserId() + "");
        // 如果没有指定商户id，则查询所有关联商户(主商户以及子商户)下的收银点
        if (merchantCashPlace.getUserId() == null) {
            List<String> userIdList = new ArrayList<>();
            for (MerchantBaseInfo merchantBaseInfo : all) {
                userIdList.add(merchantBaseInfo.getUserId());
            }

            qW.in(!userIdList.isEmpty(), "userId", userIdList);
        } else {
            // 校验查询的userId 是否合法
            boolean flag = true;
            for (MerchantBaseInfo merchantBaseInfo : all) {
                if (merchantBaseInfo.getUserId().equals(merchantCashPlace.getUserId() + "")) {
                    flag = false;
                    break;
                }
            }

            if (flag) {
                throw new MsgException("拒绝访问");
            }

            qW.eq("userId", merchantCashPlace.getUserId());
        }

        qW.eq(merchantCashPlace.getCode() != null, "code", merchantCashPlace.getCode());
        qW.like(StringUtils.isNotEmpty(merchantCashPlace.getName()), "name", merchantCashPlace.getName());

        page = page(page, qW);

        List<MerchantCashPlaceVO> result = new ArrayList<>();

        MerchantCashPlaceConverter converter = MerchantCashPlaceConverter.INSTANCE;

        List<Integer> cashPlaceIdList = new ArrayList<>();

        for (MerchantCashPlace cashPlace : page.getRecords()) {
            cashPlaceIdList.add(cashPlace.getId());
            for (MerchantBaseInfo merchantBaseInfo : all) {
                MerchantCashPlaceVO vo = converter.entity2VO(cashPlace);
                if ((vo.getUserId() + "").equals(merchantBaseInfo.getUserId())) {
                    vo.setMerchantBaseInfo(merchantBaseInfo);
                    result.add(vo);
                    break;
                }
            }
        }

        if (cashPlaceIdList.size() == 0) {
            return result;
        }

        List<MerchantCashPayCode> cashPayCodeList = cashPayCodeService.getByCashPlaceIdList(cashPlaceIdList);
        for (MerchantCashPayCode cashPayCode : cashPayCodeList) {
            for (MerchantCashPlaceVO cashPlaceVO : result) {
                if (cashPayCode.getCashPlaceId().equals(cashPlaceVO.getId())) {
                    List<String> payCodeList = cashPlaceVO.getPayCodeList();
                    if (payCodeList == null) {
                        payCodeList = new ArrayList<>();
                        cashPlaceVO.setPayCodeList(payCodeList);
                    }

                    payCodeList.add(cashPayCode.getPayCode());
                    break;
                }
            }
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindPayCode(MerchantCashPayCode merchantCashPayCode) {
        // 参数校验
        UserApp userApp = userAppService.queryUserAppByToken();
        List<MerchantBaseInfo> merchList = merchantBaseInfoService.getAllByUserId(userApp.getUserId() + "");

        MerchantCashPayCode existData = new MerchantCashPayCode().setPayCode(merchantCashPayCode.getPayCode());
        existData = cashPayCodeService.getOne(new QueryWrapper<>(existData));
        if (existData != null) {
            throw new MsgException("该收款码已绑定收银点");
        }

        Integer cashPlaceId = merchantCashPayCode.getCashPlaceId();
        if (cashPlaceId == null) {
            throw new MsgException("缺少收银点id");
        }

        MerchantCashPlace merchantCashPlace = new MerchantCashPlace().setId(cashPlaceId);
        merchantCashPlace = getOne(new QueryWrapper<>(merchantCashPlace));

        if (merchantCashPlace == null)  {
            throw new MsgException("收银点不存在");
        }

        MerchantBaseInfo cashPlaceBaseInfo = new MerchantBaseInfo().setUserId(merchantCashPlace.getUserId() + "");
        cashPlaceBaseInfo = merchantBaseInfoService.getOne(new QueryWrapper<>(cashPlaceBaseInfo));

        boolean flag = true;
        for (MerchantBaseInfo merchantBaseInfo : merchList) {
            if (merchantBaseInfo.getUserId().equals(merchantCashPlace.getUserId() + "")) {
                flag = false;
                break;
            }
        }

        if (flag) {
            throw new MsgException("拒绝访问");
        }

        if (merchantCashPayCode.getPayCode().equals(userApp.getUserId() + "")) {
            // 绑定默认的付款码，非码牌
            cashPayCodeService.bindPayCode(merchantCashPayCode);
            return;
        }

        DeviceStock deviceStock = new DeviceStock();
        deviceStock.setSnNo(merchantCashPayCode.getPayCode());
        deviceStock = deviceStockService.getOne(new QueryWrapper<>(deviceStock));
        if (deviceStock == null) {
            throw new MsgException("不存在的码牌");
        }

        String actMercId = deviceStock.getActMercId();
        if (!"3".equals(deviceStock.getStatus())) {
            deviceStockService.bindPayCode(merchantCashPayCode.getPayCode());
        }

        if (StringUtils.isNotEmpty(actMercId) && !(cashPlaceBaseInfo.getId() + "").equals(actMercId)) {
            throw new MsgException("收银点和收款码牌的所属商户不一致");
        }

        // 绑定
        cashPayCodeService.bindPayCode(merchantCashPayCode);
    }

    @Override
    public void unbindPayCode(String payCode) {
        MerchantCashPayCode cashPayCode = new MerchantCashPayCode();
        cashPayCode.setPayCode(payCode);
        cashPayCode = cashPayCodeService.getOne(new QueryWrapper<>(cashPayCode));

        if (cashPayCode == null) {
            throw new MsgException("该码牌未绑定");
        }

        MerchantCashPlace cashPlace = new MerchantCashPlace().setId(cashPayCode.getCashPlaceId());
        cashPlace = getOne(new QueryWrapper<>(cashPlace));

        // 参数校验
        UserApp userApp = userAppService.queryUserAppByToken();

        if (payCode.equals(userApp.getUserId() + "")) {
            throw new MsgException("默认收银点不允许解绑");
        }

        boolean flag = true;
        List<MerchantBaseInfo> merchList = merchantBaseInfoService.getAllByUserId(userApp.getUserId() + "");
        for (MerchantBaseInfo merchantBaseInfo : merchList) {
            if (merchantBaseInfo.getUserId().equals(cashPlace.getUserId() + "")) {
                flag = false;
                break;
            }
        }

        if (flag) {
            throw new MsgException("拒绝访问");
        }

        cashPayCodeService.unbindPayCode(payCode);
    }

    @Override
    public List<UserApp> getStaffByCode(String code) {
        return null;
    }

    @Override
    public List<UserApp> getStaffByCashPlaceId(Long id) {
        return null;
    }

    @Override
    public MerchantCashPlaceStaffVO getStatusByStaffId(String userId) {
        MerchantCashPlaceStaffVO cashPlaceStaffVO = new MerchantCashPlaceStaffVO();
        cashPlaceStaffVO.setUserId(Long.parseLong(userId));
        cashPlaceStaffVO.setStatus(MerchantCashPlaceStaff.STATUS_ONLINE);
        QueryWrapper<MerchantCashPlaceStaff> qWrapper = new QueryWrapper<>(cashPlaceStaffVO);
        qWrapper.orderByDesc("updateTime")
                .last("limit 1");
        MerchantCashPlaceStaff one = cashPlaceStaffService.getOne(qWrapper);
        cashPlaceStaffVO = Converter.INSTANCE.toVO(one);

        if (cashPlaceStaffVO != null && MerchantCashPlaceStaff.STATUS_ONLINE.equals(cashPlaceStaffVO.getStatus())) {
            MerchantCashPlace cashPlace = new MerchantCashPlace();
            cashPlace.setId(cashPlaceStaffVO.getCashPlaceId());
            cashPlace = getOne(new QueryWrapper<>(cashPlace));
            cashPlaceStaffVO.setMerchantCashPlace(cashPlace);

            val payCodeEntityList = cashPayCodeService.getByCashPlaceIdList(Collections.singletonList(cashPlace.getId()));

            val payCodeList = new ArrayList<String>();
            for (MerchantCashPayCode merchantCashPayCode : payCodeEntityList) {
                payCodeList.add(merchantCashPayCode.getPayCode());
            }
            cashPlaceStaffVO.setPayCodeList(payCodeList);

            val qWrapper2 = new QueryWrapper<MerchantBaseInfo>().eq("userId", cashPlace.getUserId());
            val mbi = merchantBaseInfoService.getOne(qWrapper2);
            cashPlaceStaffVO.setMerchantCode(mbi.getMerchantCode());
            cashPlaceStaffVO.setAlias(mbi.getAlias());
        }

        return cashPlaceStaffVO;
    }

    @Override
    public MerchantCashPlaceStaffVO getStatusByPayCode(String payCode) {
        UserApp userAppToken = userAppService.queryUserAppByToken();
        UserApp userAppBoss = new UserApp().setMerchantCode(userAppToken.getMerchantCode());
        userAppBoss.setUserType("promoter");

        userAppBoss = userAppService.getOne(new QueryWrapper<>(userAppBoss));

        MerchantCashPayCode cashPayCode = cashPayCodeService.getByPayCode(payCode);
        if (cashPayCode == null) {
            throw new MsgException("该收款码无相关收银台信息");
        }

        MerchantCashPlaceStaffVO cashPlaceStaff = new MerchantCashPlaceStaffVO();
        cashPlaceStaff.setCashPlaceId(cashPayCode.getCashPlaceId());
        QueryWrapper<MerchantCashPlaceStaff> qWrapper = new QueryWrapper<>(cashPlaceStaff);
        qWrapper.orderByDesc("updateTime").last("limit 1");

        MerchantCashPlaceStaff one = cashPlaceStaffService.getOne(qWrapper);
        cashPlaceStaff = Converter.INSTANCE.toVO(one);
        if (cashPlaceStaff == null) {
            cashPlaceStaff = new MerchantCashPlaceStaffVO();
            cashPlaceStaff.setStatus(MerchantCashPlaceStaff.STATUS_NONE);
            cashPlaceStaff.setCashPlaceId(cashPayCode.getCashPlaceId());
        } else {
            if (MerchantCashPlaceStaff.STATUS_ONLINE.equals(cashPlaceStaff.getStatus())) {
                UserApp userApp = new UserApp();
                userApp.setUserId(cashPlaceStaff.getUserId());
                userApp = userAppService.getOne(new QueryWrapper<>(userApp));
                cashPlaceStaff.setStaff(userApp);
            }
        }

        MerchantCashPlace cashPlace = new MerchantCashPlace();
        cashPlace.setId(cashPayCode.getCashPlaceId());
        cashPlace = getOne(new QueryWrapper<>(cashPlace));

        if (!cashPlace.getUserId().equals(userAppBoss.getUserId())) {
            throw new MsgException("拒绝访问");
        }

        cashPlaceStaff.setMerchantCashPlace(cashPlace);

        return cashPlaceStaff;
    }

    /**
     * 设置收银点信息
     * @date: 2021/11/29 10:57
     * @param order: 订单信息
     * @param snNo:  设别号
     */
    @Override
    public void setOrderPlaceInfo(MerchantOrder order,String snNo) {
        if(StringUtil.isNotEmpty(snNo)){
            order.setSnNo(snNo);
            QueryWrapper<MerchantCashPayCode> cashCodeQueryWrapper = new QueryWrapper<MerchantCashPayCode>().eq("payCode",snNo);
            List<MerchantCashPayCode> merchantCashPayCodes = merchantCashPayCodeMapper.selectList(cashCodeQueryWrapper);
            if(!merchantCashPayCodes.isEmpty()){
                MerchantCashPayCode cashPayCode = merchantCashPayCodes.get(0);
                order.setCashPlaceId(String.valueOf(cashPayCode.getCashPlaceId()));
                QueryWrapper<MerchantCashPlaceStaff> queryWrapper = new QueryWrapper<MerchantCashPlaceStaff>().eq("cashPlaceId",cashPayCode.getCashPlaceId())
                        .eq("status",MerchantCashPlaceStaff.STATUS_ONLINE);
                List<MerchantCashPlaceStaff> placeStaffList = merchantCashPlaceStaffMapper.selectList(queryWrapper);
                if(!placeStaffList.isEmpty()){
                    MerchantCashPlaceStaff placeStaff = placeStaffList.get(0);
                    order.setStaffCode(String.valueOf(placeStaff.getUserId()));
                    UserApp app = userAppMapper.selectByUserId(placeStaff.getUserId());
                    if(app != null){
                        order.setStaffName(app.getUserName());
                    }
                }
            }
        }
    }
}
