package com.ruoyi.cai.ws.cache;


import cn.hutool.json.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.cai.ws.bean.RoomData;
import com.ruoyi.cai.ws.constant.RedisConstant;
import com.ruoyi.cai.ws.constant.RoomStatusEnums;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.poi.ss.formula.functions.Roman;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

@Component
public class RoomDataCache {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public String getKey(Long roomId){
        return String.format(RedisConstant.ROOM_DATA,roomId);
    }

    public RoomData getByRoomId(Long roomId){
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(getKey(roomId));
        if(map.get("roomId") == null){
            return null;
        }
        return JSON.parseObject(JSON.toJSONString(map),RoomData.class);
    }

    public void init(RoomData roomData) {
        Map<String,Object> map = JSON.parseObject(JSON.toJSONString(roomData));
        stringRedisTemplate.opsForHash().putAll(getKey(roomData.getRoomId()),map);
    }

    public void hMSet(Long roomId,Map<String,Object> data) {
        String key = getKey(roomId);
        stringRedisTemplate.opsForHash().putAll(key,data);
    }

    public void hMSet(Long roomId,String mKey,Object mData) {
        String key = getKey(roomId);
        stringRedisTemplate.opsForHash().put(key,mKey,mData);
    }


    private final static String HANG_UP = "local hangupTime = tonumber(redis.call('hGet', KEYS[1], 'hangupTime'))\n" +
            "if hangupTime > 0 then\n" +
            "  return 0\n" +
            "end\n" +
            "return redis.call('hMSet', KEYS[1], 'status', 8, 'hangupTime', ARGV[1])";

    public boolean hangUp(Long roomId) {
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(HANG_UP,Boolean.class);
        String currentTime = String.valueOf(System.currentTimeMillis() / 1000);
        Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)), currentTime);
        return BooleanUtils.isTrue(execute);
    }

    public void setStatus(Long roomId, RoomStatusEnums status) {
        String key = getKey(roomId);
        stringRedisTemplate.opsForHash().put(key,"status",status.getCode());
    }

    private final static String SET_STATUS_RECEIVER_CONNECTION = "local status = tonumber(redis.call('hget', KEYS[1], 'status'))\n" +
            "if status ~= 1  then\n" +
            "  return 0\n" +
            "end\n" +
            "return redis.call('hmset', KEYS[1], 'status', 3)";

    public boolean setStatusReceiverConnection(Long roomId) {
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(SET_STATUS_RECEIVER_CONNECTION,Boolean.class);
        Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)));
        return BooleanUtils.isTrue(execute);
    }

    private final static String SET_STATUS_AGREE =
            "local status = tonumber(redis.call('hget', KEYS[1], 'status'))\n" +
            "local beginTime = tonumber(redis.call('hget', KEYS[1], 'beginTime'))\n" +
            "if status ~= 3 or beginTime > 0 then\n" +
            "  return 0\n" +
            "end\n" +
            "return redis.call('hmset', KEYS[1], 'status', 7, 'beginTime', ARGV[1])";

    public boolean setStatusAgree(Long roomId) {
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(SET_STATUS_AGREE,Boolean.class);
        String currentTime = String.valueOf(System.currentTimeMillis() / 1000);
        Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)),currentTime);
        return BooleanUtils.isTrue(execute);
    }
}
