package incheon.com.cmm.context;

import incheon.com.security.vo.LoginVO;
import lombok.Getter;
import lombok.Setter;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 요청 컨텍스트 데이터 홀더
 * ThreadLocal에 저장될 실제 데이터 객체
 *
 * 포함 정보:
 * - 사용자 정보 (LoginVO)
 * - 메뉴/시스템 정보 (메뉴코드, 시스템코드)
 * - HTTP 요청 정보 (Request, URI, Method)
 * - 확장 속성 (커스텀 데이터)
 *
 * @author Incheon Geo Platform
 * @since 2025-10-29
 */
@Getter
@Setter
public class RequestContextHolder implements Serializable {

    private static final long serialVersionUID = 1L;

    // === 사용자 정보 ===

    /** 현재 로그인 사용자 */
    private LoginVO loginUser;

    // === 메뉴/시스템 정보 ===

    /** 현재 활성 메뉴 코드 */
    private String currentMenuCd;

    /** 현재 활성 메뉴 명 */
    private String currentMenuNm;

    /** 현재 시스템 코드 (AGS, RES, SGP 등) */
    private String currentSysCd;

    /** 현재 시스템 명 */
    private String currentSysNm;

    // === HTTP 요청 정보 ===

    /** 원본 Request 객체 */
    private transient HttpServletRequest request;

    /** 요청 URI */
    private String requestUri;

    /** HTTP Method (GET, POST 등) */
    private String requestMethod;

    // === 확장 속성 ===

    /** 커스텀 속성 맵 (필요 시 추가 데이터 저장) */
    private Map<String, Object> attributes;

    // === 타임스탬프 ===

    /** 컨텍스트 생성 시각 */
    private LocalDateTime createdAt;

    /**
     * 기본 생성자
     */
    public RequestContextHolder() {
        this.attributes = new HashMap<>();
        this.createdAt = LocalDateTime.now();
    }

    /**
     * 커스텀 속성 설정
     *
     * @param key 속성 키
     * @param value 속성 값
     */
    public void setAttribute(String key, Object value) {
        this.attributes.put(key, value);
    }

    /**
     * 커스텀 속성 조회
     *
     * @param key 속성 키
     * @return 속성 값 (없으면 null)
     */
    public Object getAttribute(String key) {
        return this.attributes.get(key);
    }

    /**
     * 커스텀 속성 제거
     *
     * @param key 속성 키
     */
    public void removeAttribute(String key) {
        this.attributes.remove(key);
    }

    /**
     * Deep Copy 생성 (비동기 작업 전파용)
     *
     * 비동기 작업(@Async)에서 컨텍스트를 전파할 때 사용
     *
     * @return 복사된 컨텍스트 홀더
     */
    public RequestContextHolder snapshot() {
        RequestContextHolder copy = new RequestContextHolder();

        // 사용자 정보 복사 (참조)
        copy.loginUser = this.loginUser;

        // 메뉴/시스템 정보 복사
        copy.currentMenuCd = this.currentMenuCd;
        copy.currentMenuNm = this.currentMenuNm;
        copy.currentSysCd = this.currentSysCd;
        copy.currentSysNm = this.currentSysNm;

        // HTTP 요청 정보 복사 (request는 제외 - 스레드 안전하지 않음)
        copy.requestUri = this.requestUri;
        copy.requestMethod = this.requestMethod;

        // 확장 속성 복사 (새 Map 생성)
        copy.attributes = new HashMap<>(this.attributes);

        // 타임스탬프 복사
        copy.createdAt = this.createdAt;

        return copy;
    }

    /**
     * 로그인 여부 확인
     *
     * @return 로그인 여부
     */
    public boolean isAuthenticated() {
        return this.loginUser != null && this.loginUser.getUserId() != null;
    }

    /**
     * 현재 사용자 ID 조회
     *
     * @return 사용자 ID (로그인하지 않은 경우 null)
     */
    public String getUserId() {
        return this.loginUser != null ? this.loginUser.getUserId() : null;
    }

    /**
     * 현재 사용자 이름 조회
     *
     * @return 사용자 이름 (로그인하지 않은 경우 null)
     */
    public String getUserName() {
        return this.loginUser != null ? this.loginUser.getUserNm() : null;
    }

    @Override
    public String toString() {
        return "RequestContextHolder{" +
                "userId=" + getUserId() +
                ", userNm=" + getUserName() +
                ", currentMenuCd='" + currentMenuCd + '\'' +
                ", currentSysCd='" + currentSysCd + '\'' +
                ", requestUri='" + requestUri + '\'' +
                ", requestMethod='" + requestMethod + '\'' +
                ", createdAt=" + createdAt +
                '}';
    }
}
