import { describe, expect, test } from "bun:test";
import { MemoryQueue } from "@/queue/memory-queue.js";
import { PollRunner } from "@/poller/poll-runner.js";
import { METRIC } from "@/metrics/names.js";
import { FakeMetrics } from "../_helpers/fake-metrics.js";
import { mockLogger } from "../_helpers/mock-logger.js";
import type { JobPayload } from "@/types/index.js";

function makeJiraPayload(): JobPayload {
  return {
    jobKind: "jira",
    issueId: "10001",
    issueKey: "INT-1",
    summary: "Integration test job",
    description: "desc",
  };
}

describe("observability integration: busy queue makes the poller observable, not silent", () => {
  test("PollRunner over a real busy MemoryQueue emits poll.skipped{busy}", async () => {
    const metrics = new FakeMetrics();
    const queue = new MemoryQueue(mockLogger(), { metrics });

    // Arm a slow job that holds the queue slot until we release it
    let release: () => void = () => {};
    const slow = new Promise<void>((r) => {
      release = r;
    });

    queue.start(async () => {
      await slow;
      return "completed";
    });

    await queue.enqueue(makeJiraPayload());

    // Give the job a moment to start and set processing = true
    await new Promise((r) => setTimeout(r, 10));
    expect(queue.isBusy()).toBe(true);

    // Wire a PollRunner with skipLogThrottleMs=0 so every skip is logged
    const runner = new PollRunner({
      poller: "jira",
      queue,
      metrics,
      logger: mockLogger(),
      contendingKinds: [],
      skipLogThrottleMs: 0,
    });

    let bodyRan = false;
    const n = await runner.run(async () => {
      bodyRan = true;
      return 1;
    });

    // The poller body must NOT have run — the queue was busy
    expect(bodyRan).toBe(false);
    expect(n).toBe(0);

    // The skip must have been recorded with the correct tags
    expect(metrics.tagsOf(METRIC.pollSkipped)).toContainEqual({ poller: "jira", reason: "busy" });

    // Clean up: unblock the job and stop the queue
    release();
    await new Promise((r) => setTimeout(r, 10));
    queue.stop();
  });
});
