import type { SessionStatus } from "../../shared/types";

export interface TokenPayload {
  accessToken: string;
  refreshToken?: string;
  expiresIn?: number;
  expiresAt?: string;
  username?: string;
}

export interface PersistedSession {
  accessToken: string;
  refreshToken?: string;
  username?: string;
  expiresAt?: string;
}

export class SessionState {
  private accessToken?: string;
  private refreshToken?: string;
  private username?: string;
  private expiresAt?: string;

  set(payload: TokenPayload): SessionStatus {
    this.accessToken = payload.accessToken;
    this.refreshToken = payload.refreshToken;
    this.username = payload.username;
    this.expiresAt =
      payload.expiresAt ??
      (payload.expiresIn
        ? new Date(Date.now() + payload.expiresIn * 1000).toISOString()
        : undefined);

    return this.status();
  }

  restore(payload: PersistedSession): SessionStatus {
    this.accessToken = payload.accessToken;
    this.refreshToken = payload.refreshToken;
    this.username = payload.username;
    this.expiresAt = payload.expiresAt;
    return this.status();
  }

  clear(): SessionStatus {
    this.accessToken = undefined;
    this.refreshToken = undefined;
    this.username = undefined;
    this.expiresAt = undefined;
    return this.status();
  }

  token(): string | undefined {
    if (this.isExpired()) {
      return undefined;
    }
    return this.accessToken;
  }

  refresh(): string | undefined {
    return this.refreshToken;
  }

  isExpired(skewMs = 0): boolean {
    if (!this.accessToken || !this.expiresAt) {
      return false;
    }

    const expiresAt = Date.parse(this.expiresAt);
    return Number.isFinite(expiresAt) && expiresAt <= Date.now() + skewMs;
  }

  snapshot(): PersistedSession | undefined {
    if (!this.accessToken) {
      return undefined;
    }

    return {
      accessToken: this.accessToken,
      refreshToken: this.refreshToken,
      username: this.username,
      expiresAt: this.expiresAt
    };
  }

  status(): SessionStatus {
    return {
      authenticated: Boolean(this.token()),
      username: this.username,
      expiresAt: this.expiresAt
    };
  }
}
