import type { StateStore, OutageRecord } from "./stateStore";
import type { YouTrackClient } from "./youtrackClient";

export const CHECK_DELAYS_MS = [0, 60_000, 300_000]; // t=0, +1min, +5min (relative to recovery start)

export interface RecoveryDeps {
  store: StateStore;
  yt: Pick<YouTrackClient, "setState" | "setAssignee" | "addComment" | "getState">;
  siteFetch: (url: string) => Promise<number>;
  discord: (content: string) => Promise<void>;
  env: Env;
  now: () => number;
  hetznerSummary: string;
}

export async function beginRecovery(rec: OutageRecord, store: StateStore, now: number): Promise<void> {
  rec.status = "verifying";
  rec.checksDone = 0;
  rec.nextCheckAt = now;
  await store.put(rec);
}

function isoOf(ms: number): string {
  return new Date(ms).toISOString();
}

async function finishResolved(rec: OutageRecord, d: RecoveryDeps): Promise<void> {
  const ts = isoOf(d.now());
  if (rec.ticketId) {
    const state = await d.yt.getState(rec.ticketId);
    if (state !== "Done" && state !== "Duplicate") {
      await d.yt.setState(rec.ticketId, d.env.STATE_IN_REVIEW);
      await d.yt.addComment(rec.ticketId, `Site ${ts}'te geri geldi (HTTP 200). Hetzner: ${d.hetznerSummary}`);
    }
  }
  await d.discord(
    `✅ **${d.env.SITE_LABEL} geri geldi** (HTTP 200) — ${ts}\nTicket ${rec.ticketReadable ?? "?"} → ${d.env.STATE_IN_REVIEW}. Hetzner: ${d.hetznerSummary}`,
  );
  rec.status = "done";
  rec.nextCheckAt = null;
  await d.store.put(rec);
}

async function finishEscalated(rec: OutageRecord, code: number, d: RecoveryDeps): Promise<void> {
  if (rec.ticketId) {
    await d.yt.setAssignee(rec.ticketId, d.env.ASSIGNEE_FALLBACK);
    await d.yt.addComment(
      rec.ticketId,
      `Sentry resolve dedi ama Worker 5dk boyunca HTTP ${code} aldı — alt katman (Horizon/queue/DB) kontrol edilmeli. Hetzner: ${d.hetznerSummary}`,
    );
  }
  await d.discord(
    `⚠️ **${d.env.SITE_LABEL}:** Sentry recovered dedi ama Worker 5dk boyunca HTTP ${code} alıyor — alt katman kontrol gerek. Ticket ${rec.ticketReadable ?? "?"} → ${d.env.ASSIGNEE_FALLBACK}.`,
  );
  rec.status = "done";
  rec.nextCheckAt = null;
  await d.store.put(rec);
}

async function processOne(rec: OutageRecord, d: RecoveryDeps): Promise<void> {
  const code = await d.siteFetch(d.env.SITE_URL);
  rec.checksDone += 1;
  rec.lastStatusCode = code;

  if (code === 200) {
    await finishResolved(rec, d);
    return;
  }

  if (rec.checksDone >= CHECK_DELAYS_MS.length) {
    await finishEscalated(rec, code, d);
    return;
  }

  // schedule the next check relative to "now" using the inter-check delta
  const delta = CHECK_DELAYS_MS[rec.checksDone] - CHECK_DELAYS_MS[rec.checksDone - 1];
  rec.nextCheckAt = d.now() + delta;
  await d.store.put(rec);
}

export async function runDueRecoveries(d: RecoveryDeps): Promise<void> {
  const now = d.now();
  for (const rec of await d.store.listVerifying()) {
    if (rec.nextCheckAt !== null && rec.nextCheckAt <= now) {
      await processOne(rec, d);
    }
  }
}
