package com.ruoyi.bst.booth.service.impl;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import com.github.pagehelper.PageHelper;
import com.ruoyi.bst.booth.service.BoothValidator;
import com.ruoyi.bst.changeRecord.domain.ChangeRecord;
import com.ruoyi.bst.changeRecord.domain.enums.ChangeRecordBstType;
import com.ruoyi.bst.changeRecord.mapper.ChangeRecordMapper;
import com.ruoyi.bst.device.domain.DeviceQuery;
import com.ruoyi.bst.device.domain.DeviceVO;
import com.ruoyi.bst.device.domain.vo.DeviceIotVO;
import com.ruoyi.bst.device.mapper.DeviceMapper;
import com.ruoyi.bst.device.service.DeviceIotService;
import com.ruoyi.bst.device.service.DeviceService;
import com.ruoyi.bst.lightingNum.domain.LightingNum;
import com.ruoyi.bst.lightingNum.domain.LightingNumQuery;
import com.ruoyi.bst.lightingNum.domain.LightingNumVO;
import com.ruoyi.bst.lightingNum.mapper.LightingNumMapper;
import com.ruoyi.bst.lightingNum.service.LightingNumService;
import com.ruoyi.bst.order.domain.OrderQuery;
import com.ruoyi.bst.part.domain.PartVO;
import com.ruoyi.bst.part.service.PartService;
import com.ruoyi.bst.store.domain.StoreVO;
import com.ruoyi.bst.store.mapper.StoreMapper;
import com.ruoyi.bst.storeStaff.domain.enums.StoreStaffPermission;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.iot.constants.IotConstants;
import com.ruoyi.iot.domain.response.CommandResponse;
import com.ruoyi.iot.service.IotService;
import com.ruoyi.iot.util.IotUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.bst.booth.mapper.BoothMapper;
import com.ruoyi.bst.booth.domain.Booth;
import com.ruoyi.bst.booth.domain.BoothVO;
import com.ruoyi.bst.booth.domain.BoothQuery;
import com.ruoyi.bst.booth.service.BoothService;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 卡座Service业务层处理
 *
 * @author ruoyi
 * @date 2025-04-18
 */
@Service
public class BoothServiceImpl implements BoothService
{
    @Autowired
    private BoothMapper boothMapper;
    @Autowired
    private PartService partService;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private DeviceIotService deviceIotService;
    @Autowired
    private StoreMapper storeMapper;
    @Autowired
    private LightingNumMapper lightingNumMapper;
    @Autowired
    private IotService iotService;
    @Autowired
    private ChangeRecordMapper changeRecordMapper;
    @Autowired
    private LightingNumService lightingNumService;
    @Autowired
    private BoothValidator boothValidator;
    @Autowired
    private RedisLock redisLock;
    @Autowired
    private DeviceService deviceService;

    /**
     * 查询卡座
     *
     * @param scope 卡座主键
     * @return 卡座
     */
    @Override
    public BoothVO selectBoothByBoothId(Long id, boolean scope)
    {
        if (id == null) {
            return null;
        }
        BoothQuery query = new BoothQuery();
        query.setBoothId(id);
        query.setScope(scope);
        query.addStorePermission(StoreStaffPermission.BOOTH_VIEW.getCode());
        return this.selectOne(query);
    }

    @Override
    public BoothVO selectBoothByBoothNo(String boothNo, boolean scope)
    {
        if (boothNo == null) {
            return null;
        }
        BoothQuery query = new BoothQuery();
        query.setBoothNo(boothNo);
        query.setScope(scope);
        query.addStorePermission(StoreStaffPermission.BOOTH_VIEW.getCode());
        return this.selectOne(query);
    }


    @Override
    public BoothVO selectOne(BoothQuery query) {
        PageHelper.startPage(1, 1);
        List<BoothVO> list = this.selectBoothList(query);
        return CollectionUtils.firstElement(list);
    }
    /**
     * 查询卡座列表
     *
     * @param booth 卡座
     * @return 卡座
     */
    @Override
    public List<BoothVO> selectBoothList(BoothQuery booth)
    {
        return boothMapper.selectBoothList(booth);
    }

    /**
     * 新增卡座
     *
     * @param booth 卡座
     * @return 结果
     */
    @Override
    public int insertBooth(Booth booth)
    {
        booth.setCreateTime(DateUtils.getNowDate());
        Integer result = transactionTemplate.execute(status -> {
            int rows = boothMapper.insertBooth(booth);
            if (rows > 0) {
                // 后校验
                boothValidator.validate(booth.getBoothId(),booth.getBoothNo());
            }
            return rows;
        });
        return result == null ? 0 : result;
    }

    /**
     * 修改卡座
     *
     * @param booth 卡座
     * @return 结果
     */
    @Override
    public int updateBooth(Booth booth)
    {
        if (booth.getBoothNo()!=null) {
            boothValidator.validate(booth.getBoothId(),booth.getBoothNo());
        }
        return boothMapper.updateBooth(booth);
    }

    /**
     * 批量删除卡座
     *
     * @param boothIds 需要删除的卡座主键
     * @return 结果
     */
    @Override
    public int deleteBoothByBoothIds(List<Long> boothIds)
    {
        return boothMapper.deleteBoothByBoothIds(boothIds);
    }

    /**
     * 删除卡座信息
     *
     * @param boothId 卡座主键
     * @return 结果
     */
    @Override
    public int deleteBoothByBoothId(Long boothId)
    {
        return boothMapper.deleteBoothByBoothId(boothId);
    }

    @Override
    public BoothVO bindUser(Long userId, String boothNo) {
        boolean lock = redisLock.lock(RedisLockKey.BOOTH_BIND_USER, userId);
        ServiceUtil.assertion(!lock, "您当前操作过于频繁，请稍后重试");
        try {
            BoothQuery query = new BoothQuery();
            query.setUserId(userId);
            query.setTime(LocalDateTime.now());
            List<BoothVO> list = boothMapper.selectBoothList(query);
            ServiceUtil.assertion(list != null && !list.isEmpty(),"请勿绑定多个卡座");
            BoothVO booth = boothMapper.selectBoothByBoothNo(boothNo);
            ServiceUtil.assertion(booth==null,"当前卡座不存在");
            if (booth.getUserId()!=null&&booth.getExpiredTime() != null && booth.getExpiredTime().isAfter(LocalDateTime.now())) {
                // 卡座未过期，被其他用户绑定
                ServiceUtil.assertion(!booth.getUserId().equals(userId),"卡座已被绑定");
                // 卡座未过期，被当前用户绑定
                ServiceUtil.assertion(booth.getUserId().equals(userId),"请勿重复绑定该设备");
            }else {
                booth.setExpiredTime(LocalDateTime.now().plusMinutes(30));
                booth.setUserId(userId);
            }
            int i = boothMapper.updateBooth(booth);
            ServiceUtil.assertion(i==0,"操作失败");
            return booth;
        } finally {
            redisLock.unlock(RedisLockKey.BOOTH_BIND_USER, userId);
        }
    }


    @Override
    public void getDevices(BoothVO booth){
        DeviceQuery query = new DeviceQuery();
        query.setBoothId(booth.getBoothId());
        List<DeviceVO> devices = deviceMapper.selectDeviceList(query);
        booth.setDevices(devices);
    }

    @Override
    public int unbindUser(BoothVO booth) {
        booth.setUserId(null);
        return boothMapper.updateBooth(booth);
    }

    @Override
    public int userChangeBind(String usingBoothNo, String changeBoothNo ,Long userId) {

        BoothVO usingBooth = boothMapper.selectBoothByBoothNo(usingBoothNo);
        ServiceUtil.assertion(usingBooth == null,"编号为%s的卡座信息不存在",usingBoothNo);
        ServiceUtil.assertion(usingBooth.getUserId() == null,"请先绑定编号为%s的卡座后再进行操作",usingBoothNo);
        ServiceUtil.assertion(!usingBooth.getUserId().equals(userId),"您无权限更改当前卡座信息",usingBoothNo);
        BoothVO changeBooth = boothMapper.selectBoothByBoothNo(changeBoothNo);
        ServiceUtil.assertion(changeBooth == null,"编号为%s的卡座信息不存在",changeBoothNo);
        boolean lock = redisLock.lock(RedisLockKey.BOOTH_CHANGE_USER, changeBoothNo);
        ServiceUtil.assertion(!lock, "您当前操作过于频繁，请稍后重试");
        try {
            Integer result = transactionTemplate.execute(status -> {
                usingBooth.setUserId(null);
                int unbind = boothMapper.updateBooth(usingBooth);
                ServiceUtil.assertion(unbind != 1,"解绑当前设备失败");
                if (changeBooth.getUserId()!=null && changeBooth.getExpiredTime() != null && changeBooth.getExpiredTime().isAfter(LocalDateTime.now())) {
                    // 卡座未过期，被其他用户绑定
                    ServiceUtil.assertion(!changeBooth.getUserId().equals(userId),"卡座已被绑定");
                    // 卡座未过期，被当前用户绑定
                    ServiceUtil.assertion(changeBooth.getUserId().equals(userId),"请勿重复绑定该设备");
                }
                changeBooth.setUserId(userId);
                changeBooth.setExpiredTime(LocalDateTime.now().plusMinutes(30));
                int changeBind = boothMapper.updateBooth(changeBooth);
                ServiceUtil.assertion(changeBind != 1,"用户换绑失败");
                return changeBind;
            });
            return result;
        } finally {
            redisLock.unlock(RedisLockKey.BOOTH_CHANGE_USER, changeBoothNo);
        }
    }



    @Override
    public DeviceIotVO lighting(BoothVO booth,Long userId,boolean requiredIot) {

        // 操作校验
        ServiceUtil.assertion(booth.getStoreId()==null,"当前卡座未绑定店铺");
        ServiceUtil.assertion(booth.getExpiredTime().isBefore(LocalDateTime.now()), "请重新绑定卡座");

        // 判断当前用户是否在该店铺下有余额
        LightingNumVO vo = lightingNumMapper.selectLightingNumByUserId(userId,booth.getStoreId());
        ServiceUtil.assertion(vo == null,"请先购买余额");
        ServiceUtil.assertion(vo.getNumber()<=0,"余额不足，请充值");

        // 设备相关校验
        // 根据id查询出卡座对应的所有设备
        DeviceQuery deviceQuery = new DeviceQuery();
        deviceQuery.setBoothId(booth.getBoothId());
        deviceQuery.setDeleted(false);
        deviceQuery.setBoothNo(booth.getBoothNo());
        List<DeviceVO> deviceVOList = deviceMapper.selectDeviceList(deviceQuery);

        //
        if (deviceVOList != null && !deviceVOList.isEmpty()) {
            deviceVOList.forEach(deviceVO -> {
                ServiceUtil.assertion(deviceVO == null || deviceVO.getDeviceId() == null, "设备不存在");
                ServiceUtil.assertion(StringUtils.isAllBlank(deviceVO.getMac(), deviceVO.getMac2()), "设备MAC号为空");
                ServiceUtil.assertion(deviceVO.getDuration() == null,"设备编号为%s的设备暂未设置开启时长",deviceVO.getDeviceNo());
                if (deviceVO.getExpireTime()!=null) {
                    ServiceUtil.assertion( deviceVO.getExpireTime().isAfter(LocalDateTime.now()),"请勿在爆灯时间内重复爆灯");
                }
            });
        }

        DeviceIotVO iotVO = new DeviceIotVO();

        // 爆灯
        Integer result = transactionTemplate.execute(status -> {

            // 先扣减次数
            LightingNum data = new LightingNum();
            data.setNumber(1);
            OrderQuery query = new OrderQuery();
            query.setUserId(userId);
            query.setStoreId(booth.getStoreId());
            int i = lightingNumService.reduceLightingNumByQuery(data,query);
            iotVO.setDb(i);
            ServiceUtil.assertion(i!=1,"操作失败");
            // 新建变化记录表
            ChangeRecord changeRecord = new ChangeRecord();
            changeRecord.setBstType(ChangeRecordBstType.LIGHTING.getCode());
            changeRecord.setBstId(booth.getBoothId());
            changeRecord.setUserId(userId);
            changeRecord.setStoreId(booth.getStoreId());
            // 记录卡座ID为业务ID
            changeRecord.setBstId(booth.getBoothId());
            changeRecord.setNumber(1);
            changeRecord.setBeforeNum(vo.getNumber());
            changeRecord.setAfterNum(vo.getNumber()-1);
            changeRecord.setCreateTime(DateUtils.getNowDate());
            changeRecord.setReason("用户爆灯");
            i = changeRecordMapper.insertChangeRecord(changeRecord);
            ServiceUtil.assertion(i!=1,"操作失败");
            deviceVOList.forEach(deviceVO -> {
                boolean iotOp = this.lighting(deviceVO);
                ServiceUtil.assertion(requiredIot && !iotOp, "");
                iotVO.setIot(iotOp);
            });
            return i;
        });
        return iotVO;
    }


    @Override
    public boolean lighting(DeviceVO device) {
        Integer result = transactionTemplate.execute(status -> {
            device.setExpireTime(LocalDateTime.now().plusSeconds(device.getDuration()));
            int i = deviceService.updateDevice(device);
            ServiceUtil.assertion(i != 1,"更新设备防重复爆灯时间失败");
            CommandResponse res = iotService.setTime(device, device.getDuration(), "爆灯");
            ServiceUtil.assertion(res == null, "设备爆灯失败：未知错误");
            boolean iot = IotUtil.isSuccess(res);
            return iot? 1:0;
        });
        return MathUtils.equals(result,1);
    }
}
