import { jwtDecode } from "jwt-decode";
import { ActivityMonitor } from "../activity-monitor/activity-monitor";
import { TokenManager } from "../token-manager/token-manager";

const CHECK_INTERVAL_MS = 30_000;
const REFRESH_THRESHOLD_S = 120;
const ACTIVITY_WINDOW_MS = 15 * 60 * 1000;

export interface SessionRefreshTimer {
  start: () => void;
  stop: () => void;
}

export class SessionRefreshTimerImpl implements SessionRefreshTimer {
  private intervalId: ReturnType<typeof setInterval> | null = null;
  private isRefreshing = false;

  constructor(
    private readonly tokenManager: TokenManager,
    private readonly activityMonitor: ActivityMonitor,
  ) {}

  start = () => {
    this.intervalId = setInterval(this.checkAndRefresh, CHECK_INTERVAL_MS);
  };

  stop = () => {
    if (this.intervalId !== null) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  };

  private getTokenExpiry = (): number => {
    try {
      const { exp } = jwtDecode(this.tokenManager.getToken()) as { exp?: number };
      return exp ?? 0;
    } catch {
      return 0;
    }
  };

  private checkAndRefresh = async () => {
    const now = Date.now();

    // Skip if the user hasn't interacted in the last ACTIVITY_WINDOW_MS.
    // Avoids keeping sessions alive for unattended tabs.
    if (now - this.activityMonitor.getLastActivityTimestamp() > ACTIVITY_WINDOW_MS) return;

    // Skip if a refresh is already in flight (this interval can fire again before the previous awaits).
    if (this.isRefreshing) return;

    const exp = this.getTokenExpiry();

    // Skip if the token can't be decoded (e.g. not yet initialized).
    if (exp === 0) return;

    // exp is in seconds, now is in milliseconds — compare in the same unit.
    if (exp - now / 1000 <= REFRESH_THRESHOLD_S) {
      this.isRefreshing = true;
      try {
        await this.tokenManager.refreshToken();
      } catch {
        // tokenManager.refreshToken() publishes refreshTokenFailed via broker on failure
      } finally {
        this.isRefreshing = false;
      }
    }
  };
}

export const createSessionRefreshTimer = (
  tokenManager: TokenManager,
  activityMonitor: ActivityMonitor,
): SessionRefreshTimer => new SessionRefreshTimerImpl(tokenManager, activityMonitor);
