/**
 * 세션 관리 유틸리티
 * 세션 만료 감지, 자동 로그아웃, 세션 갱신 등을 담당
 *
 * 모바일/데스크톱 환경별 타임아웃 설정:
 * - 데스크톱: 30분 비활성 시 만료, 5분 전 경고
 * - 모바일: 24시간 비활성 시 만료, 1시간 전 경고 (WebView localStorage 초기화 이슈 대응)
 */

interface SessionConfig {
  checkInterval: number; // 세션 체크 간격 (ms)
  warningTime: number; // 만료 경고 시간 (ms)
  maxInactiveTime: number; // 최대 비활성 시간 (ms)
}

interface SessionWarningCallbacks {
  onWarning?: (remainingTime: number) => void;
  onExpiry?: () => void;
  onActivity?: () => void;
}

export class SessionManager {
  private config: SessionConfig;
  private callbacks: SessionWarningCallbacks;
  private checkTimer: NodeJS.Timeout | null = null;
  private warningTimer: NodeJS.Timeout | null = null;
  private lastActivity: number = Date.now();
  private isWarningShown: boolean = false;

  constructor(config: Partial<SessionConfig> = {}, callbacks: SessionWarningCallbacks = {}) {
    this.config = {
      checkInterval: 60000, // 1분마다 체크
      warningTime: 300000, // 5분 전 경고
      maxInactiveTime: 1800000, // 30분 비활성 시 만료
      ...config,
    };

    this.callbacks = callbacks;
    this.setupActivityListeners();
  }

  /**
   * 세션 모니터링 시작
   */
  start() {
    this.stop(); // 기존 타이머 정리

    this.checkTimer = setInterval(() => {
      this.checkSession();
    }, this.config.checkInterval);
  }

  /**
   * 세션 모니터링 중지
   */
  stop() {
    if (this.checkTimer) {
      clearInterval(this.checkTimer);
      this.checkTimer = null;
    }

    if (this.warningTimer) {
      clearTimeout(this.warningTimer);
      this.warningTimer = null;
    }

    this.removeActivityListeners();
  }

  /**
   * 사용자 활동 기록
   */
  recordActivity() {
    this.lastActivity = Date.now();
    this.isWarningShown = false;

    // 경고 타이머가 있다면 취소
    if (this.warningTimer) {
      clearTimeout(this.warningTimer);
      this.warningTimer = null;
    }

    this.callbacks.onActivity?.();
  }

  /**
   * 세션 상태 확인
   */
  private checkSession() {
    const now = Date.now();
    const timeSinceLastActivity = now - this.lastActivity;
    const timeUntilExpiry = this.config.maxInactiveTime - timeSinceLastActivity;

    // 세션 만료 체크
    if (timeSinceLastActivity >= this.config.maxInactiveTime) {
      this.handleSessionExpiry();
      return;
    }

    // 경고 시간 체크
    if (timeUntilExpiry <= this.config.warningTime && !this.isWarningShown) {
      this.showSessionWarning(timeUntilExpiry);
    }
  }

  /**
   * 세션 만료 경고 표시
   */
  private showSessionWarning(remainingTime: number) {
    this.isWarningShown = true;
    this.callbacks.onWarning?.(remainingTime);

    // 남은 시간 후 자동 만료
    this.warningTimer = setTimeout(() => {
      this.handleSessionExpiry();
    }, remainingTime);
  }

  /**
   * 세션 만료 처리
   */
  private handleSessionExpiry() {
    this.stop();
    this.callbacks.onExpiry?.();
  }

  /**
   * 활동 리스너 설정
   */
  private setupActivityListeners() {
    // 사용자 활동 이벤트들
    const activityEvents = ["mousedown", "mousemove", "keypress", "scroll", "touchstart", "click"];

    // 각 이벤트에 대해 리스너 등록
    activityEvents.forEach((event) => {
      document.addEventListener(event, this.handleActivity, true);
    });

    // 페이지 가시성 변경 이벤트
    document.addEventListener("visibilitychange", this.handleVisibilityChange);
  }

  /**
   * 활동 리스너 제거
   */
  private removeActivityListeners() {
    const activityEvents = ["mousedown", "mousemove", "keypress", "scroll", "touchstart", "click"];

    activityEvents.forEach((event) => {
      document.removeEventListener(event, this.handleActivity, true);
    });

    document.removeEventListener("visibilitychange", this.handleVisibilityChange);
  }

  /**
   * 활동 이벤트 핸들러
   */
  private handleActivity = () => {
    this.recordActivity();
  };

  /**
   * 페이지 가시성 변경 핸들러
   */
  private handleVisibilityChange = () => {
    if (!document.hidden) {
      this.recordActivity();
    }
  };

  /**
   * 현재 세션 상태 정보 반환
   */
  getSessionInfo() {
    const now = Date.now();
    const timeSinceLastActivity = now - this.lastActivity;
    const timeUntilExpiry = this.config.maxInactiveTime - timeSinceLastActivity;

    return {
      lastActivity: this.lastActivity,
      timeSinceLastActivity,
      timeUntilExpiry: Math.max(0, timeUntilExpiry),
      isActive: timeSinceLastActivity < this.config.maxInactiveTime,
      isWarningShown: this.isWarningShown,
    };
  }
}

/**
 * 시간을 분:초 형식으로 포맷
 */
export function formatTime(milliseconds: number): string {
  const seconds = Math.floor(milliseconds / 1000);
  const minutes = Math.floor(seconds / 60);
  const remainingSeconds = seconds % 60;

  return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
}

/**
 * 전역 세션 매니저 인스턴스
 */
let globalSessionManager: SessionManager | null = null;

/**
 * 전역 세션 매니저 초기화
 */
export function initSessionManager(
  config: Partial<SessionConfig> = {},
  callbacks: SessionWarningCallbacks = {},
): SessionManager {
  if (globalSessionManager) {
    globalSessionManager.stop();
  }

  globalSessionManager = new SessionManager(config, callbacks);
  return globalSessionManager;
}

/**
 * 전역 세션 매니저 가져오기
 */
export function getSessionManager(): SessionManager | null {
  return globalSessionManager;
}

/**
 * 세션 매니저 정리
 */
export function cleanupSessionManager() {
  if (globalSessionManager) {
    globalSessionManager.stop();
    globalSessionManager = null;
  }
}

export default SessionManager;

/**
 * 토큰 동기화 유틸리티
 */
export const tokenSync = {
  // 토큰 상태 확인
  checkToken: () => {
    const token = localStorage.getItem("authToken");
    return !!token;
  },

  // 토큰 강제 동기화 (다른 탭에서 설정된 토큰을 현재 탭에 복사)
  forceSync: () => {
    const token = localStorage.getItem("authToken");
    if (token) {
      // sessionStorage에도 복사
      sessionStorage.setItem("authToken", token);
      return true;
    }
    return false;
  },

  // 토큰 복원 시도 (sessionStorage에서 복원)
  restoreFromSession: () => {
    const sessionToken = sessionStorage.getItem("authToken");
    if (sessionToken) {
      localStorage.setItem("authToken", sessionToken);
      return true;
    }
    return false;
  },

  // 토큰 유효성 검증
  validateToken: (token: string) => {
    if (!token) return false;

    try {
      // JWT 토큰 구조 확인 (header.payload.signature)
      const parts = token.split(".");
      if (parts.length !== 3) return false;

      // payload 디코딩 시도
      const payload = JSON.parse(atob(parts[1]));
      const now = Math.floor(Date.now() / 1000);

      // 만료 시간 확인
      if (payload.exp && payload.exp < now) {
        return false;
      }

      return true;
    } catch (error) {
      return false;
    }
  },
};
