import type {
  IntervalTaskOptions,
  TaskOptions,
} from "@c/backgroundTasks/taskManagerTypes"
import type { FastifyInstance } from "fastify"
import fastifyPlugin from "fastify-plugin"
import { SimpleIntervalJob, AsyncTask, ToadScheduler } from "toad-scheduler"

// Store metadata for jobs
const taskMetadata = new Map<string, { keepRunning: boolean }>()

let activeConnections = 0
let isAppReady = false
let tasksToStartOnReady: Array<() => void> = []

const pauseNonEssentialTasks = (fastify: FastifyInstance) => {
  const jobs = fastify.scheduler.getAllJobs()
  jobs.forEach((job) => {
    const metadata = taskMetadata.get(job.id || "")
    if (metadata && !metadata.keepRunning) {
      fastify.log.info(`Pausing non-essential task: ${job.id}`)
      job.stop()
    }
  })
}

const resumeNonEssentialTasks = (fastify: FastifyInstance) => {
  const jobs = fastify.scheduler.getAllJobs()
  jobs.forEach((job) => {
    const metadata = taskMetadata.get(job.id || "")
    if (metadata && !metadata.keepRunning) {
      fastify.log.info(`Resuming non-essential task: ${job.id}`)
      job.start()
    }
  })
}

const stopAllTasks = (fastify: FastifyInstance) => {
  const jobs = fastify.scheduler.getAllJobs()
  fastify.log.info(`Stopping ${jobs.length} tasks...`)

  jobs.forEach((job) => {
    try {
      job.stop()
      fastify.log.debug(`Stopped task: ${job.id}`)
    } catch (error) {
      fastify.log.error(`Error stopping task ${job.id}:`, error)
    }
  })

  // Clear all jobs from scheduler
  try {
    fastify.scheduler.stop()
    fastify.log.info("Task scheduler stopped")
  } catch (error) {
    fastify.log.error("Error stopping scheduler:", error)
  }

  // Clear metadata
  taskMetadata.clear()
  tasksToStartOnReady = []
}

const setupTaskManager = (fastify: FastifyInstance) => {
  fastify.wss.on("connection", (socket) => {
    activeConnections++
    if (activeConnections === 1) {
      resumeNonEssentialTasks(fastify)
    }

    socket.on("disconnect", () => {
      activeConnections--
      if (activeConnections === 0) {
        pauseNonEssentialTasks(fastify)
      }
    })
  })

  return {
    createIntervalTask: (
      name: string,
      handler: () => Promise<void>,
      options: IntervalTaskOptions,
    ) => {
      const createTask = () => {
        const task = new AsyncTask(name, handler, (error: Error) => {
          if (options.errorHandler) {
            options.errorHandler(error)
          }
          fastify.log.error(`Task ${name} failed:`, error)
        })

        const job = new SimpleIntervalJob(
          {
            seconds: options.seconds,
            runImmediately: options.runImmediately ?? false,
          },
          task,
          { id: name },
        )

        taskMetadata.set(name, {
          keepRunning: options.keepRunning ?? false,
        })

        fastify.scheduler.addSimpleIntervalJob(job)
        fastify.log.info(`Registered interval task: ${name}`)
      }

      // If app is ready, create task immediately
      // Otherwise, queue it for when the app becomes ready
      if (isAppReady) {
        createTask()
      } else {
        tasksToStartOnReady.push(createTask)
        fastify.log.info(`Queued task for app ready: ${name}`)
      }
    },

    cancelTask: (name: string) => {
      const removed = fastify.scheduler.removeById(name)

      if (removed) {
        taskMetadata.delete(name)
        fastify.log.info(`Canceled task: ${name}`)
      } else {
        fastify.log.warn(`Task not found: ${name}`)
      }
    },

    markAppReady: () => {
      if (isAppReady) return

      isAppReady = true
      fastify.log.info(
        `App ready, starting ${tasksToStartOnReady.length} queued tasks`,
      )

      // Start all queued tasks
      tasksToStartOnReady.forEach((createTask) => {
        try {
          createTask()
        } catch (error) {
          fastify.log.error("Error starting queued task:", error)
        }
      })

      tasksToStartOnReady = []
    },

    stopAllTasks: () => stopAllTasks(fastify),

    getTaskCount: () => fastify.scheduler.getAllJobs().length,
  }
}

export default fastifyPlugin(
  async (fastify: FastifyInstance) => {
    const taskManager = setupTaskManager(fastify)

    fastify.decorate("taskManager", taskManager)

    // Add cleanup hook for server shutdown
    fastify.addHook("onClose", async () => {
      fastify.log.info("App is closing, stopping all tasks...")
      stopAllTasks(fastify)
    })
  },
  {
    name: "taskManager",
  },
)

export { setupTaskManager, type TaskOptions, type IntervalTaskOptions }
