package com.takensoft.common.util;

import jakarta.servlet.http.HttpSession;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author takensoft
 * @since 2025.03.21
 * @modification
 *     since    |    author    | description
 *  2025.03.21  |  takensoft   | 최초 등록
 *  2025.05.29  |  takensoft   | Redis 통합 중복로그인 관리
 *
 * 세션 로그인 방식의 유틸리티 - Redis 통합
 */
@Component
public class SessionUtil {

    private final Map<String, HttpSession> sessionMap = new ConcurrentHashMap<>();
    private final RedisTemplate<String, String> redisTemplate;

    public SessionUtil(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 세션 등록 - Redis 연동
     * 기존 세션 있으면 강제 로그아웃 후 새 세션 등록
     */
    public synchronized void registerSession(String mbrId, HttpSession newSession) {
        try {
            // 1. 기존 메모리 세션 처리
            HttpSession oldSession = sessionMap.get(mbrId);
            if (oldSession != null && oldSession != newSession) {
                try {
                    oldSession.invalidate();
                } catch (IllegalStateException e) {
                }
            }

            // 2. 새 세션을 메모리에 등록
            sessionMap.put(mbrId, newSession);

            // 3. Redis에 세션 정보 저장 (중복로그인 관리용)
            String sessionKey = "session:" + mbrId;
            redisTemplate.opsForValue().set(sessionKey, newSession.getId(),
                    Duration.ofSeconds(newSession.getMaxInactiveInterval()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 세션 ID로 세션 무효화
     */
    public void invalidateSessionById(String sessionId) {
        try {
            boolean found = false;
            // 메모리에서 해당 세션 ID를 가진 세션 찾아서 무효화
            sessionMap.entrySet().removeIf(entry -> {
                HttpSession session = entry.getValue();
                if (session != null && session.getId().equals(sessionId)) {
                    try {
                        session.invalidate();
                        return true;
                    } catch (IllegalStateException e) {
                        return true;
                    }
                }
                return false;
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 사용자별 세션 제거 - Redis 연동
     */
    public void removeSession(String mbrId) {
        try {
            // 1. 메모리 세션 무효화
            HttpSession session = sessionMap.get(mbrId);
            if (session != null) {
                try {
                    session.invalidate();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                }
            }
            sessionMap.remove(mbrId);

            // 2. Redis에서도 제거
            String sessionKey = "session:" + mbrId;
            redisTemplate.delete(sessionKey);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 전체 세션 무효화 - Redis 연동
     */
    public void invalidateAllSessions() {
        try {
            // 1. 모든 메모리 세션 무효화
            for (Map.Entry<String, HttpSession> entry : sessionMap.entrySet()) {
                HttpSession session = entry.getValue();
                if (session != null) {
                    try {
                        session.invalidate();
                    } catch (IllegalStateException e) {
                        e.printStackTrace();
                    }
                }
            }
            sessionMap.clear();

            // 2. Redis에서 모든 세션 키 삭제
            try {
                var sessionKeys = redisTemplate.keys("session:*");
                if (sessionKeys != null && !sessionKeys.isEmpty()) {
                    redisTemplate.delete(sessionKeys);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 현재 활성 세션 수 조회
     */
    public int getActiveSessionCount() {
        return sessionMap.size();
    }

    /**
     * 특정 사용자의 세션 존재 여부 확인
     */
    public boolean hasActiveSession(String mbrId) {
        HttpSession session = sessionMap.get(mbrId);
        if (session == null) {
            return false;
        }

        try {
            // 세션이 유효한지 확인
            session.getAttribute("mbrId");
            return true;
        } catch (IllegalStateException e) {
            // 세션이 무효화됨
            sessionMap.remove(mbrId);
            return false;
        }
    }

    /**
     * Redis에서 세션 정보 확인
     */
    public boolean isValidSessionInRedis(String mbrId, String sessionId) {
        try {
            String sessionKey = "session:" + mbrId;
            String storedSessionId = redisTemplate.opsForValue().get(sessionKey);
            return storedSessionId != null && storedSessionId.equals(sessionId);
        } catch (Exception e) {
            return false;
        }
    }
}