package com.usky.system.service.util;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.utils.StringUtils;
import com.usky.common.core.util.SpringContextUtils;
import com.usky.common.log.aspect.AddressUtils;
import com.usky.common.redis.core.RedisService;
import com.usky.system.domain.MceRequestVO;
import com.usky.system.domain.SysLogininfor;
import com.usky.system.domain.SysUser;
import com.usky.system.mapper.SysUserMapper;
import com.usky.system.model.LoginUser;
import com.usky.system.service.ISysLogininforService;
import com.usky.system.service.MceReceiveService;
import eu.bitwalker.useragentutils.UserAgent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.usky.common.core.utils.ip.IpUtils.getIpAddr;

/**
 * @description: 异步工厂（产生任务用）
 * @author: XiaoYu
 * @date: 2024/08/20 13:58
 */
@Component
public class AsyncFactory {
    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");

    private static final MceReceiveService mceReceiveService = SpringContextUtils.getBean(MceReceiveService.class);

    public static final SysUserMapper SYS_USER_MAPPER = SpringContextUtils.getBean(SysUserMapper.class);

    /**
     * 记录登录信息
     *
     * @param username 用户名
     * @param status 状态
     * @param message 消息
     * @param args 列表
     * @return 任务task
     */
    public static void recordLoginInfo(HttpServletRequest request, final Integer tenantId, final String username, final String status, final String message, final Integer deptId, final Object... args) {
        final UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        final String ip = request != null ? getIpAddr(request) : "未知";
        String address = "未知"; // 默认地址为未知
        if (request != null) {
            address = AddressUtils.getRealAddressByIP(ip);
        }
        StringBuilder s = new StringBuilder();
        s.append(getBlock(ip));
        s.append(address);
        s.append(getBlock(username));
        s.append(getBlock(status));
        s.append(getBlock(message));
        // 打印信息到日志
        sys_user_logger.info(s.toString(), args);
        // 获取客户端操作系统
        String os = userAgent.getOperatingSystem().getName();
        // 获取客户端浏览器
        String browser = userAgent.getBrowser().getName();
        // 封装对象
        SysLogininfor logininfor = new SysLogininfor();
        logininfor.setUserName(username);
        logininfor.setIpaddr(ip);
        logininfor.setLoginLocation(address);
        logininfor.setBrowser(browser);
        logininfor.setOs(os);
        logininfor.setMsg(message);
        logininfor.setCreateBy(username);
        logininfor.setTenantId(tenantId);
        logininfor.setDeptId(deptId);
        // 日志状态
        if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
            logininfor.setStatus(String.valueOf(Constants.LOGIN_SUCCESS_STATUS)); // 使用String.valueOf进行转换

            // 如果登录成功，发送微信公众号消息
            if (Constants.LOGIN_SUCCESS.equals(status)) {
                sendWeChatMessage(logininfor);
                // 保留用户相同OS的最新1条token，删除其他所有token
                SpringContextUtils.getBean(AsyncFactory.class).asyncRetainLatestToken(username);
            }
        } else if (Constants.LOGIN_FAIL.equals(status)) {
            logininfor.setStatus(String.valueOf(Constants.LOGIN_FAIL_STATUS)); // 使用String.valueOf进行转换
        }
        sys_user_logger.info("log is {}", JSON.toJSONString(logininfor));
        // 插入数据
        SpringContextUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
    }

    public static String getBlock(Object msg) {
        if (msg == null) {
            msg = "";
        }
        return "[" + msg.toString() + "]";
    }

    private static void sendWeChatMessage(SysLogininfor logininfor) {
        MceRequestVO mceRequestVO = new MceRequestVO();
        mceRequestVO.setInfoTitle("登录成功通知");
        mceRequestVO.setInfoContent("用户 "+logininfor.getUserName() +" 登录成功!");
        mceRequestVO.setInfoType("0");
        mceRequestVO.setInfoTypeName("登录通知");
        mceRequestVO.setUserName(logininfor.getUserName());

        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(SysUser::getUserId)
                .eq(SysUser::getUserName, logininfor.getUserName());
        SysUser sysUser = SYS_USER_MAPPER.selectOne(queryWrapper);

        mceRequestVO.setUserIds(Collections.singletonList(sysUser.getUserId()));

        mceRequestVO.setUserName(logininfor.getUserName());
        mceRequestVO.setLoginAddress(logininfor.getLoginLocation());
        mceRequestVO.setLoginType(logininfor.getOs() + "-" + logininfor.getBrowser());
        mceRequestVO.setIpAddress(logininfor.getIpaddr());
        mceReceiveService.addMceReceive(mceRequestVO);
    }

    /**
     * 异步清理历史token
     *
     * @param username 用户名
     */
    @Async
    public void asyncRetainLatestToken(String username) {
        try {
            // 等待2秒
            TimeUnit.SECONDS.sleep(2);
            // 调用清理token的方法
            retainLatestToken(username);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            sys_user_logger.error("异步清理token时发生错误", e);
        }
    }

    /**
     * 保留用户相同OS的最新一个token，删除其他历史token
     *
     * @param username 用户名
     */
    private static void retainLatestToken(String username) {
        RedisService redisService = SpringContextUtils.getBean(RedisService.class);

        try {
            // 获取所有与该用户相关的token键
            String pattern = CacheConstants.LOGIN_TOKEN_KEY + "*";
            Collection<String> keys = redisService.keys(pattern);
            if (keys == null || keys.isEmpty()) {
                sys_user_logger.warn("Redis密钥为null或为空");
                return;
            }

            // 存储该用户的token及其对应的LoginUser对象
            Map<String, LoginUser> userTokens = new HashMap<>();

            for (String key : keys) {
                // 检查键是否存在并且未过期
                if (redisService.hasKey(key)) {
                    LoginUser user = redisService.getCacheObject(key);
                    sys_user_logger.info("从Redis获取的LoginUser对象: {}", user);
                    if (user != null && username.equals(user.getUsername())) {
                        userTokens.put(key, user);
                    }
                }
            }

            if (userTokens.isEmpty()) {
                sys_user_logger.warn("未找到用户 {} 的任何token", username);
                return;
            }

            // 分组逻辑：根据OS分组
            Map<String, List<Map.Entry<String, LoginUser>>> groupedTokens = new HashMap<>();
            for (Map.Entry<String, LoginUser> entry : userTokens.entrySet()) {
                LoginUser loginUser = entry.getValue();
                String os = StringUtils.isEmpty(loginUser.getOs()) ? "未知" : loginUser.getOs();
                groupedTokens.computeIfAbsent(os, k -> new ArrayList<>()).add(entry);
            }

            // 删除列表
            List<String> tokensToDelete = new ArrayList<>();
            for (List<Map.Entry<String, LoginUser>> entryList : groupedTokens.values()) {
                // 按照登录时间降序排序
                entryList.sort((e1, e2) ->
                        e2.getValue().getLoginTime().compareTo(e1.getValue().getLoginTime())
                );

                // 只保留最新的一个token，其余的都添加到tokensToDelete列表中
                for (int i = 1; i < entryList.size(); i++) {
                    String keyToDelete = entryList.get(i).getKey();
                    tokensToDelete.add(keyToDelete);
                }
            }

            // 删除其他token
            sys_user_logger.info("要删除的token列表: {}", tokensToDelete);
            for (String keyToDelete : tokensToDelete) {
                if (keyToDelete != null) {
                    // 再次检查键是否存在
                    if (redisService.hasKey(keyToDelete)) {
                        boolean deleted = redisService.deleteObject(keyToDelete);
                        sys_user_logger.info("Deleted Token Key: " + keyToDelete + ", Result: " + deleted);
                    } else {
                        sys_user_logger.warn("尝试删除的token键 {} 不存在，跳过删除操作", keyToDelete);
                    }
                } else {
                    sys_user_logger.warn("尝试删除的token键为null，跳过删除操作");
                }
            }

            sys_user_logger.info("用户 {} 的token已清理，仅保留每种OS的最新token: 已删除{}个", username, tokensToDelete.size());
        } catch (Exception ex) {
            sys_user_logger.error("清理用户 {} 的token时发生错误", username, ex);
        }
    }
}