package com.ruoyi.cai.ws.cache;


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.redisson.api.RMap;
import org.redisson.api.RScript;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Collections;
import java.util.Map;

/**
 * 房间信息
 * 在拨打电话的时候就已经提前初始化
 * <p>created on 2024/1/11 22:49</p>
 * @author duet
 */
@Component
public class RoomDataCache {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

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

    public RoomData getByRoomId(Long roomId){
        RMap<String, Object> map = redissonClient.getMap(getKey(roomId));
        Map<String, Object> allMap = map.readAllMap();
//        Map<Object, Object> map = redisTemplate.opsForHash().entries(getKey(roomId));
        if(allMap.get("roomId") == null){
            return null;
        }
        return JSON.parseObject(JSON.toJSONString(allMap),RoomData.class);
    }

    public void init(RoomData roomData) {
        Map<String,Object> map = JSON.parseObject(JSON.toJSONString(roomData));
//        redisTemplate.opsForHash().putAll(getKey(roomData.getRoomId()),map);
        RMap<String, Object> mapRedis = redissonClient.getMap(getKey(roomData.getRoomId()));
        mapRedis.putAll(map);
        mapRedis.expire(Duration.ofDays(15));
    }

    public void hMSet(Long roomId,Map<String,Object> data) {
        String key = getKey(roomId);
//        redisTemplate.opsForHash().putAll(key,data);
        RMap<Object, Object> map = redissonClient.getMap(key);
        map.putAll(data);
    }

    public void hMSet(Long roomId,String mKey,Object mData) {
        String key = getKey(roomId);
        RMap<String, Object> map = redissonClient.getMap(key);
        map.put(mKey,mData);
//        redisTemplate.opsForHash().put(key,mKey,mData);
    }


    private final static String HANG_UP = "local hangupTime = tonumber(redis.call('hGet', KEYS[1], '\"hangupTime\"'))\n" +
            "if hangupTime and 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) {
        RScript script = redissonClient.getScript();
        Long currentTime = System.currentTimeMillis() / 1000;
        Boolean execute = script.eval(RScript.Mode.READ_WRITE, HANG_UP, RScript.ReturnType.BOOLEAN,
                Collections.singletonList(getKey(roomId)), currentTime);
//        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(HANG_UP,Boolean.class);
//        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);
//        redisTemplate.opsForHash().put(key,"status",status.getCode());
        RMap<String, Object> map = redissonClient.getMap(key);
        map.put("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) {
        RScript script = redissonClient.getScript();
        Boolean execute = script.eval(RScript.Mode.READ_WRITE, SET_STATUS_RECEIVER_CONNECTION, RScript.ReturnType.BOOLEAN,
                Collections.singletonList(getKey(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 and 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) {
        String currentTime = String.valueOf(System.currentTimeMillis() / 1000);
        RScript script = redissonClient.getScript();
        Boolean execute = script.eval(RScript.Mode.READ_WRITE, SET_STATUS_AGREE, RScript.ReturnType.BOOLEAN,
                Collections.singletonList(getKey(roomId)),currentTime);
//        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(SET_STATUS_AGREE,Boolean.class);
//        Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)),currentTime);
        return BooleanUtils.isTrue(execute);
    }

    private final static String INCS_BLACK_AMOUNT =
            "redis.call('hIncrBy', KEYS[1], '\"payCoin\"', ARGV[1])\n" +
            "redis.call('hIncrBy', KEYS[1], '\"payIncome\"', ARGV[2])";

    public boolean incsBlackAmount(Long roomId, Long decrCoin, Long decrIncomeCoin) {
        RScript script = redissonClient.getScript();
        Boolean execute = script.eval(RScript.Mode.READ_WRITE, INCS_BLACK_AMOUNT, RScript.ReturnType.BOOLEAN,
                Collections.singletonList(getKey(roomId)),decrCoin.intValue(),decrIncomeCoin.intValue());
//        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(INCS_BLACK_AMOUNT,Boolean.class);
//        Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)),
//                decrCoin,decrIncomeCoin);
        return BooleanUtils.isTrue(execute);
    }
}
