import { logInfo, logWarn } from "./logger";
import { env } from "./env";

export class UpstreamMonitor {
  private static isDown = false;
  private static recoveryTimer: NodeJS.Timeout | null = null;
  private static subscribers: (() => Promise<void> | void)[] = [];
  private static downSubscribers: (() => Promise<void> | void)[] = [];

  static isUpstreamDown() {
    return this.isDown;
  }

  static async checkHealth(): Promise<boolean> {
    try {
      const baseUrl = env.GetString("UPDOT_CORE_BASE_URL");
      const healthUrl = `${baseUrl}/v2/member/authorization/email`;
      // Use fetch from global scope (Node 18+)
      const res = await fetch(healthUrl, { method: "HEAD" });
      return res.status < 500;
    } catch {
      return false;
    }
  }

  static onRecovered(callback: () => Promise<void> | void) {
    this.subscribers.push(callback);
  }

  static onDown(callback: () => Promise<void> | void) {
    this.downSubscribers.push(callback);
  }

  static async notifyDown(label: string) {
    if (this.isDown) return;
    this.isDown = true;
    logWarn(`[UpstreamMonitor] Upstream down detected from ${label}. Global operations paused.`);

    // Notify down subscribers
    for (const sub of this.downSubscribers) {
      try {
        await sub();
      } catch (err) {
        console.error("[UpstreamMonitor] Down subscriber error:", err);
      }
    }

    if (this.recoveryTimer) return;

    this.recoveryTimer = setInterval(async () => {
      const healthy = await this.checkHealth();
      if (healthy) {
        logInfo("[UpstreamMonitor] Upstream recovered. Notifying subscribers.");
        this.isDown = false;
        if (this.recoveryTimer) {
          clearInterval(this.recoveryTimer);
          this.recoveryTimer = null;
        }
        
        for (const sub of this.subscribers) {
          try {
            await sub();
          } catch (err) {
            console.error("[UpstreamMonitor] Subscriber error:", err);
          }
        }
      }
    }, 60000); // Check every minute
  }
}
