package com.red.circle.live.infra.database.cache.service.impl;

import com.alibaba.fastjson.JSON;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.live.domain.live.LiveMicrophone;
import com.red.circle.live.infra.database.cache.key.LiveMicKey;
import com.red.circle.live.infra.database.cache.service.LiveMicCacheService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.func.VoidConsumer;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 麦克风用户缓存服务.
 *
 * @author pengliang on 2023/12/11
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LiveMicCacheServiceImpl implements LiveMicCacheService {

  private final RedisService redisService;

  @Override
  public boolean checkLockMic(Long roomId, Integer index) {
    return redisService.hash(LiveMicKey.LOCK.getKey(roomId, index));
  }

  @Override
  public boolean lockMicOps(Long roomId, Integer index) {
    return redisService.setIfAbsent(LiveMicKey.LOCK.getKey(roomId, index), 1, 1, TimeUnit.MINUTES);
  }

  @Override
  public void unLockMicOps(Long roomId, Integer index) {
    redisService.delete(LiveMicKey.LOCK.getKey(roomId, index));
  }

  @Override
  public void tryMicOpsLock(Long roomId, Integer index, VoidConsumer voidConsumer) {
    if (!lockMicOps(roomId, index)) {
      return;
    }
    try {
      voidConsumer.accept();
    } finally {
      unLockMicOps(roomId, index);
    }
  }

  @Override
  public boolean checkAvailable(Long roomId, Integer index) {
    return !redisService.hashHasKey(LiveMicKey.SEAT.getKey(roomId), Objects.toString(index));
  }

  @Override
  public void goUp(Long roomId, Integer index, LiveMicrophone microphone) {
//    if (Objects.isNull(microphone.getRefreshTime())) {
//      microphone.updateLastActivityTime();
//    }
    microphone.updateLastActivityTime();
    log.info("用户上麦 index = {} microphone = {} ", index, JSON.toJSONString(microphone));
    redisService.hashPut(LiveMicKey.SEAT.getKey(roomId),
        Objects.toString(index),
        microphone);
  }

  @Override
  public void goDown(Long roomId, Integer index) {
    redisService.hashDelete(LiveMicKey.SEAT.getKey(roomId), Objects.toString(index));
  }

  @Override
  public void goDown(Long roomId, List<Integer> index) {
    redisService.hashDelete(LiveMicKey.SEAT.getKey(roomId),
        index.stream().map(Objects::toString).toArray(String[]::new));
  }

  @Override
  public void goDownAll(Long roomId) {
    redisService.delete(LiveMicKey.SEAT.getKey(roomId));
  }

  @Override
  public boolean checkEqSelf(Long roomId, Integer index, Long userId) {
    LiveMicrophone microphone = redisService.hashGet(LiveMicKey.SEAT.getKey(roomId),
        Objects.toString(index),
        LiveMicrophone.class);

    return Objects.nonNull(microphone)
        && Objects.nonNull(microphone.getUser())
        && Objects.equals(microphone.getUser().getId(), userId);
  }

  @Override
  public List<LiveMicrophone> listLiveMicrophone(Long roomId) {
    return redisService.hashGetValues(LiveMicKey.SEAT.getKey(roomId), LiveMicrophone.class);
  }

  @Override
  public LiveMicrophone getLiveMicrophone(Long roomId, Integer index) {
    return redisService.hashGet(LiveMicKey.SEAT.getKey(roomId), Objects.toString(index),
        LiveMicrophone.class);
  }

  @Override
  public List<LiveMicrophone> listLiveMicrophone(Long roomId, Long userId) {
    List<LiveMicrophone> liveMicrophones = listLiveMicrophone(roomId);

    if (CollectionUtils.isEmpty(liveMicrophones)) {
      return CollectionUtils.newArrayList();
    }

    return liveMicrophones.stream().filter(mic -> Objects.equals(mic.getUser().getId(), userId))
        .toList();
  }

  @Override
  public boolean refreshNotActiveUser(Long roomId) {
    setExpire(roomId);

    List<LiveMicrophone> liveMicrophone = listLiveMicrophone(roomId);
    if (CollectionUtils.isEmpty(liveMicrophone)) {
      return false;
    }

    String[] index =
        liveMicrophone.stream().filter(LiveMicrophone::checkInactiveExpire)
            .map(LiveMicrophone::getMicIndex)
            .map(Objects::toString)
            .toArray(String[]::new);

    log.info("清除不活跃的用户入参 = {} ", JSON.toJSONString(index));
    Long size = redisService.hashDelete(LiveMicKey.SEAT.getKey(roomId), index);
    log.info("清除不活跃的用户结果 = {} ", size);

    return Objects.nonNull(size) && size > 0;
  }


  private void setExpire(Long roomId) {
    redisService.expire(LiveMicKey.SEAT.getKey(roomId), 120, TimeUnit.SECONDS);
  }

}
