import { Injectable, computed, signal } from '@angular/core';

/**
 * Makes rate limiting visible to the UI.
 *
 * Without this a 429 is indistinguishable from a generic failure: the user
 * sees "something went wrong" while the correct message is "you are being
 * throttled, this resumes in N seconds."
 */

export interface RateLimitState {
  readonly active: boolean;
  readonly retryAfterSeconds: number;
  readonly lastUrl?: string;
  readonly since?: number;
}

const IDLE: RateLimitState = { active: false, retryAfterSeconds: 0 };

@Injectable({ providedIn: 'root' })
export class RateLimitNotifier {
  private readonly state = signal<RateLimitState>(IDLE);
  private clearTimer: ReturnType<typeof setTimeout> | null = null;

  readonly current = this.state.asReadonly();
  readonly isRateLimited = computed(() => this.state().active);
  readonly retryAfterSeconds = computed(() => this.state().retryAfterSeconds);

  /** Called by the HTTP interceptor when a 429 is observed. */
  report(retryAfterSeconds: number, url?: string): void {
    const seconds = Math.max(0, Math.ceil(retryAfterSeconds));

    this.state.set({
      active: true,
      retryAfterSeconds: seconds,
      lastUrl: url,
      since: Date.now(),
    });

    // Self-clearing: a banner that outlives the throttle is worse than no
    // banner, because it trains users to ignore it.
    this.cancelTimer();
    this.clearTimer = setTimeout(() => this.clear(), Math.max(1, seconds) * 1000);
  }

  clear(): void {
    this.cancelTimer();
    this.state.set(IDLE);
  }

  private cancelTimer(): void {
    if (this.clearTimer !== null) {
      clearTimeout(this.clearTimer);
      this.clearTimer = null;
    }
  }
}
