package egovframework.util;

import egovframework.constant.SessionConstants;
import go.kr.project.login.model.LoginUserVO;
import go.kr.project.login.model.SessionVO;
import go.kr.project.system.group.model.GroupVO;
import go.kr.project.system.menu.model.MenuVO;
import go.kr.project.system.role.model.RoleVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;

/**
 * packageName    : egovframework.util
 * fileName       : SessionUtil
 * author         : 시스템 관리자
 * date           : 2025-05-15
 * description    : 세션 정보를 쉽게 가져올 수 있는 유틸리티 클래스
 * ===========================================================
 * DATE              AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2025-05-15        시스템 관리자       최초 생성
 */
@Slf4j
public class SessionUtil {

    // 세션 키는 SessionConstants 클래스에서 관리

    /**
     * 현재 요청의 HttpServletRequest 객체를 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return HttpServletRequest 객체, 요청 컨텍스트가 없는 경우 null
     */
    public static HttpServletRequest getRequest() {
        try {
            ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
            return attr.getRequest();
        } catch (IllegalStateException e) {
            // 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우
            log.debug("HTTP 요청 컨텍스트가 없습니다. (배치 작업 또는 비웹 컨텍스트)");
            return null;
        }
    }

    /**
     * 현재 요청의 HttpSession 객체를 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return HttpSession 객체, 요청 컨텍스트가 없는 경우 null
     */
    public static HttpSession getSession() {
        HttpServletRequest request = getRequest();
        return request != null ? request.getSession() : null;
    }

    /**
     * 현재 세션에서 SessionVO 객체를 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return SessionVO 객체, 세션이 없는 경우 null
     */
    public static SessionVO getSessionVO() {
        HttpSession session = getSession();
        if (session != null) {
            return (SessionVO) session.getAttribute(SessionConstants.SESSION_KEY);
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자 정보를 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자 정보, 로그인하지 않은 경우 null
     */
    public static LoginUserVO getLoginUser() {
        SessionVO sessionVO = getSessionVO();
        if (sessionVO != null && sessionVO.isLogin()) {
            return sessionVO.getUser();
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자의 ID를 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자의 ID, 로그인하지 않은 경우 null
     */
    public static String getUserId() {
        LoginUserVO user = getLoginUser();
        if (user != null) {
            return user.getUserId();
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자의 이름을 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자의 이름, 로그인하지 않은 경우 null
     */
    public static String getUserName() {
        LoginUserVO user = getLoginUser();
        if (user != null) {
            return user.getUserNm();
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자의 계정을 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자의 계정, 로그인하지 않은 경우 null
     */
    public static String getUserAccount() {
        LoginUserVO user = getLoginUser();
        if (user != null) {
            return user.getUserAcnt();
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자의 그룹 정보를 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자의 그룹 정보, 그룹 정보가 없는 경우 null
     */
    public static GroupVO getUserGroup() {
        SessionVO sessionVO = getSessionVO();
        if (sessionVO != null && sessionVO.isLogin()) {
            return sessionVO.getGroup();
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자의 역할 정보 목록을 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자의 역할 정보 목록, 역할 정보가 없는 경우 null
     */
    public static List<RoleVO> getUserRoles() {
        SessionVO sessionVO = getSessionVO();
        if (sessionVO != null) {
            return sessionVO.getRoles();
        }
        return null;
    }

    /**
     * 현재 로그인한 사용자의 메뉴 정보 목록을 가져옵니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 null을 반환합니다.
     * 
     * @return 로그인한 사용자의 메뉴 정보 목록, 메뉴 정보가 없는 경우 null
     */
    public static List<MenuVO> getUserMenus() {
        SessionVO sessionVO = getSessionVO();
        if (sessionVO != null) {
            return sessionVO.getMenus();
        }
        return null;
    }

    /**
     * 현재 로그인 여부를 확인합니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 false를 반환합니다.
     * 
     * @return 로그인 여부
     */
    public static boolean isLogin() {
        SessionVO sessionVO = getSessionVO();
        return sessionVO != null && sessionVO.isLogin();
    }

    /**
     * 현재 방문자 여부를 확인합니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 false를 반환합니다.
     * 
     * @return 방문자 여부
     */
    public static boolean isVisitor() {
        SessionVO sessionVO = getSessionVO();
        return sessionVO != null && sessionVO.isVisitor();
    }

    /**
     * 현재 시스템 관리자 여부를 확인합니다.
     * 배치 작업 등에서 HTTP 요청 컨텍스트가 없는 경우 false를 반환합니다.
     *
     * @return 시스템 관리자 여부
     */
    public static boolean isSystem() {
        SessionVO sessionVO = getSessionVO();
        return sessionVO != null && sessionVO.isSystem();
    }

    /**
     * 배치 작업에서 사용할 수 있는 시스템 관리자 여부를 확인합니다.
     * 배치 작업은 시스템 권한으로 실행되는 것으로 간주합니다.
     *
     * @return 배치 작업의 시스템 권한 여부 (항상 true)
     */
    public static boolean isBatchSystem() {
        // 배치 작업은 시스템 권한으로 실행
        return true;
    }

    /**
     * 배치 작업에서 사용할 수 있는 배치 사용자 ID를 반환합니다.
     * 배치 작업은 시스템 배치 사용자로 간주합니다.
     *
     * @return 배치 사용자 ID
     */
    public static String getBatchUserId() {
        return "BATCH_SYSTEM";
    }

    /**
     * 배치 작업에서 사용할 수 있는 배치 사용자 계정을 반환합니다.
     *
     * @return 배치 사용자 계정
     */
    public static String getBatchUserAccount() {
        return "BATCH_SYSTEM";
    }
}
