import fp from 'fastify-plugin';
import type { FastifyInstance } from 'fastify';
import { Queue, Worker } from 'bullmq';
import { Redis } from 'ioredis';
import { eq } from 'drizzle-orm';
import { devices } from '../db/schema/index.js';
import { pollZkDevice } from '../modules/devices/zklib.poller.js';

declare module 'fastify' {
  interface FastifyInstance {
    zkPollQueue: Queue;
  }
}

function makeBullMqConnection(url: string) {
  return new Redis(url, { maxRetriesPerRequest: null, enableReadyCheck: false });
}

export default fp(async function queuePlugin(fastify: FastifyInstance) {
  const queueConn = makeBullMqConnection(fastify.config.REDIS_URL);
  const workerConn = makeBullMqConnection(fastify.config.REDIS_URL);

  const zkPollQueue = new Queue('zk-poll', { connection: queueConn });
  fastify.decorate('zkPollQueue', zkPollQueue);

  const worker = new Worker(
    'zk-poll',
    async (job) => {
      const { deviceId } = job.data as { deviceId: string };
      await pollZkDevice(fastify, deviceId);
    },
    { connection: workerConn }
  );

  worker.on('failed', (job, err) => {
    fastify.log.error({ jobId: job?.id, err }, 'ZK poll job failed');
  });

  fastify.addHook('onClose', async () => {
    await worker.close();
    await zkPollQueue.close();
    queueConn.disconnect();
    workerConn.disconnect();
  });

  fastify.addHook('onReady', async () => {
    const zkDevices = await fastify.db
      .select({ id: devices.id })
      .from(devices)
      .where(eq(devices.commMode, 'ZKLIB'));

    for (const device of zkDevices) {
      await zkPollQueue.add(
        `poll-${device.id}`,
        { deviceId: device.id },
        { repeat: { every: 30000 }, jobId: `poll-${device.id}` }
      );
    }

    fastify.log.info({ count: zkDevices.length }, 'ZKLib poll jobs registered');
  });
});
