import type { FastifyInstance } from "fastify";
import { DEAD_LETTER_QUEUE_NAME, JOB_QUEUE_NAME } from "@app/shared-types";
import { Queue, Job } from "bullmq";

interface JobSummary {
  id: string | undefined;
  name: string;
  data: unknown;
  failedReason: string | undefined;
  attemptsMade: number;
  timestamp: number;
}

export async function adminWorkersRoutes(app: FastifyInstance) {
  const admin = { preHandler: [app.requireAdmin] };
  const dlq = new Queue(DEAD_LETTER_QUEUE_NAME, { connection: app.redis });

  app.addHook("onClose", async () => {
    await dlq.close();
  });

  app.get("/admin/v1/workers/health", admin, async (_req, reply) => {
    const queue = new Queue(JOB_QUEUE_NAME, { connection: app.redis });
    const [jobCounts, dlqCounts, workers, schedulers] = await Promise.all([
      queue.getJobCounts("wait", "active", "delayed", "completed", "failed"),
      dlq.getJobCounts("wait", "active", "completed", "failed"),
      queue.getWorkers(),
      queue.getJobSchedulers(),
    ]);
    await queue.close();

    return reply.send({
      ok: true,
      queues: {
        jobs: jobCounts,
        deadLetter: dlqCounts,
      },
      workers: workers.map((w) => ({
        id: w.id,
        addr: w.addr,
        concurrency: w.concurrency,
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        lastSeenAt: (w as any).ts,
      })),
      schedulers: schedulers.map((s) => ({ id: s.id, pattern: s.pattern, every: s.every })),
    });
  });

  app.get("/admin/v1/workers/dead-letter", admin, async (req, reply) => {
    const limit = Math.min(Number((req.query as { limit?: string }).limit ?? 50), 200);
    const jobs = await dlq.getJobs(["wait", "failed"], 0, limit - 1, true);
    const summary: JobSummary[] = jobs.map((job) => ({
      id: job.id,
      name: job.name,
      data: job.data,
      failedReason: job.failedReason,
      attemptsMade: job.attemptsMade,
      timestamp: job.timestamp,
    }));
    return reply.send({ jobs: summary });
  });

  app.post("/admin/v1/workers/dead-letter/:id/retry", admin, async (req, reply) => {
    const { id } = req.params as { id: string };
    const job = await Job.fromId(dlq, id);
    if (!job) {
      return reply.status(404).send({ error: { code: "NOT_FOUND", message: "Jobbet finns inte i dead letter queue." } });
    }

    const mainQueue = new Queue(JOB_QUEUE_NAME, { connection: app.redis });
    await mainQueue.add(job.name, job.data, {
      attempts: 3,
      backoff: { type: "exponential", delay: 2_000 },
    });
    await job.remove();
    await mainQueue.close();

    return reply.send({ ok: true, message: "Jobbet har lagts tillbaka i kön." });
  });

  app.post("/admin/v1/workers/dead-letter/:id/discard", admin, async (req, reply) => {
    const { id } = req.params as { id: string };
    const job = await Job.fromId(dlq, id);
    if (!job) {
      return reply.status(404).send({ error: { code: "NOT_FOUND", message: "Jobbet finns inte i dead letter queue." } });
    }
    await job.remove();
    return reply.send({ ok: true, message: "Jobbet har tagits bort från dead letter queue." });
  });
}
