package com.qiaoba.auth.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.api.auth.constants.SecurityConstant;
import com.qiaoba.api.auth.entity.OnlineUser;
import com.qiaoba.api.auth.entity.dto.OnlineUserDto;
import com.qiaoba.api.auth.service.AuthConfigApiService;
import com.qiaoba.api.auth.service.OnlineUserService;
import com.qiaoba.api.auth.utils.TokenUtil;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.entity.BasePage;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.common.redis.service.RedisService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 在线用户 服务层实现
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/5/25 17:15
 */
@Service
@RequiredArgsConstructor
public class OnlineUserServiceImpl implements OnlineUserService {

    private final RedisService redisService;
    private final HttpServletRequest request;
    private final AuthConfigApiService authConfigApiService;

    @Override
    public void insert(OnlineUser onlineUser) {
        redisService.set(handleKey(onlineUser.getUsername(), onlineUser.getDeviceSn()), onlineUser, TokenUtil.TOKEN_EXPIRE_HOUR_TIME * 3600);
    }

    @Override
    public void deleteOne(String username, String deviceSn, Boolean deleteOwn) {

        if (!deleteOwn && isOwn(deviceSn)) {
            throw new ServiceException("禁止踢出自己！");
        }

        // 删除在线用户信息
        redisService.del(handleKey(username, deviceSn));

        // 允许同时在线
        if (authConfigApiService.checkAllowBothOnline()) {
            // > 1 说明还有其他设备登录着  不能删除 userDetail ||  == 1 说明没有其他设备  可以删除 userDetail
            if (redisService.hSize(SecurityConstant.LOGIN_USER_DEVICES_REDIS_KEY + username) <= 1) {
                // 删除 userDetail
                redisService.del(SecurityConstant.USER_DETAILS_REDIS_KEY + username);
            }
        }
        // 不允许同时在线
        else {
            // 最后登录的设备是自己 可以删除 userDetail
            if (checkIsLastLogged(username, deviceSn)) {
                redisService.del(SecurityConstant.USER_DETAILS_REDIS_KEY + username);
            }
        }

        // 删除最后登录的用户设备
        if (deviceSn.equals(redisService.get(SecurityConstant.LAST_LOGIN_USER_REDIS_KEY + username))) {
            redisService.del(SecurityConstant.LAST_LOGIN_USER_REDIS_KEY + username);
        }
        // 删除 hash中的自己
        redisService.hDel(SecurityConstant.LOGIN_USER_DEVICES_REDIS_KEY + username, deviceSn);
    }

    @Override
    public void deleteAll(String username) {

    }

    @Override
    public OnlineUser selectOne(String username, String deviceSn) {
        return redisService.getObject(handleKey(username, deviceSn), OnlineUser.class);
    }

    @Override
    public List<OnlineUser> selectList(String username) {
        String key = SecurityConstant.ONLINE_USER_REDIS_KEY + "*";
        if (StrUtil.isNotBlank(username)) {
            key = key + username + "*";
        }

        List<OnlineUser> users = new ArrayList<>();
        Collection<String> keys = redisService.getKeys(key);
        for (String temp : keys) {
            users.add(redisService.getObject(redisService.removeTenantPrefix(temp), OnlineUser.class));
        }
        return users;
    }

    @Override
    public Boolean checkIsLastLogged(String username, String deviceSn) {
        String loggedDevice = redisService.get(SecurityConstant.LAST_LOGIN_USER_REDIS_KEY + username).toString();
        return deviceSn.equals(loggedDevice);
    }

    @Override
    public BasePage<OnlineUser> selectPageList(Integer pageNum, Integer pageSize, String username) {
        String key = SecurityConstant.ONLINE_USER_REDIS_KEY + "*";
        if (StrUtil.isNotBlank(username)) {
            key = key + username + "*";
        }
        List<String> allKeys = CollUtil.newArrayList(redisService.getKeys(key));
        List<String> keys = CollUtil.page(pageNum - 1, pageSize, allKeys);
        List<OnlineUser> users = new ArrayList<>();
        for (String temp : keys) {
            users.add(redisService.getObject(redisService.removeTenantPrefix(temp), OnlineUser.class));
        }
        return BasePage.build(((Integer) allKeys.size()).longValue(), users);
    }

    private String handleKey(String key, String deviceSn) {
        return SecurityConstant.ONLINE_USER_REDIS_KEY + key + BaseConstant.COLON_JOIN_STR + deviceSn;
    }

    private Boolean isOwn(String deviceSn) {
        String token = TokenUtil.getToken(request, false);
        OnlineUserDto dto = TokenUtil.getUsernameAndDeviceSn(token);
        return deviceSn.equals(dto.getDeviceSn());
    }
}
