import type { Logger } from "pino";
import { METRIC } from "@/metrics/names.js";
import type { Metrics } from "@/metrics/types.js";

export type Integration = "jira" | "slack" | "github" | "agent";

export interface AuthProbe {
  integration: Integration;
  /** Resolves true when the credential authenticates. Throwing counts as false. */
  check: () => Promise<boolean>;
}

export interface AuthCheckerDeps {
  metrics: Metrics;
  logger: Logger;
  intervalMs: number;
  probes: AuthProbe[];
}

export class AuthChecker {
  private timer: ReturnType<typeof setInterval> | null = null;
  private lastOk = new Map<Integration, boolean>();

  constructor(private readonly deps: AuthCheckerDeps) {}

  start(): void {
    if (this.timer) return;
    void this.checkAll();
    this.timer = setInterval(() => void this.checkAll(), this.deps.intervalMs);
  }

  stop(): void {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  }

  async checkAll(): Promise<void> {
    await Promise.all(this.deps.probes.map((p) => this.checkOne(p)));
  }

  private async checkOne(probe: AuthProbe): Promise<void> {
    let ok = false;
    try {
      ok = await probe.check();
    } catch {
      ok = false;
    }
    this.deps.metrics.gauge(METRIC.integrationAuthOk, ok ? 1 : 0, {
      integration: probe.integration,
    });
    const prev = this.lastOk.get(probe.integration);
    if (ok && prev === false) {
      // Real recovery: was failing, now ok
      this.deps.logger.info({ integration: probe.integration }, "integration_auth_recovered");
    } else if (!ok && prev !== false) {
      // New failure: first-time failure (prev undefined) or repeated failure — keep boot failures loud
      this.deps.logger.error({ integration: probe.integration }, "integration_auth_failed");
    }
    this.lastOk.set(probe.integration, ok);
  }
}
