import type { FastifyInstance } from "fastify"
import type { RedisKey } from "ioredis"
import type { RedisPluginOptions, RedisService } from "./redisTypes"
import fastifyPlugin from "fastify-plugin"
import { Redis } from "ioredis"

export default fastifyPlugin(
  (fastify: FastifyInstance, options: RedisPluginOptions, done: any) => {
    const url = options.url || "redis://localhost:6379"

    fastify.log.info(`[REDIS] Connecting to ${url}`)

    const client = new Redis(url, {
      retryStrategy: (times) => {
        const delay = Math.min(times * 50, 2000)

        return delay
      },
      ...options.options,
    })

    // Handle connection events
    client.on("error", (error) => {
      fastify.log.error("[REDIS] Error:", error)
    })
    client.on("connect", () => fastify.log.info("[REDIS] Connected"))
    client.on("reconnecting", () => fastify.log.info("[REDIS] Reconnecting..."))

    const redisService: RedisService = {
      get: async (key: string) => client.get(key),
      set: async (key: string, value: string, expireSeconds?: number) => {
        if (expireSeconds) {
          return client.setex(key, expireSeconds, value)
        }

        return client.set(key, value)
      },
      del: async (...args: [...keys: RedisKey[]]) => client.del(args),
      exists: async (key: string) => client.exists(key),
      incr: async (key: string) => client.incr(key),
      expire: async (key: string, seconds: number) =>
        client.expire(key, seconds),
      multi: () => client.multi() as any,
      setex: async (key: string, seconds: number, value: string) =>
        client.setex(key, seconds, value),
      mget: async (...keys: string[]) => client.mget(keys),
      keys: async (pattern: string) => client.keys(pattern),
      ttl: async (key: string) => client.ttl(key),
    }

    fastify.decorate("redis", redisService)

    fastify.addHook("onClose", async () => {
      await client.quit()
    })

    done()
  },
)
