import cron, { ScheduledTask } from 'node-cron'
import { query } from '../config/database.js'

interface ScheduledTaskEntry {
  name: string
  cron: string
  handler: () => Promise<void>
  task: ScheduledTask | null
}

const registeredTasks = new Map<string, ScheduledTaskEntry>()

const taskHandlers: Record<string, () => Promise<void>> = {}

export function registerTaskHandler(name: string, handler: () => Promise<void>) {
  taskHandlers[name] = handler
}

async function executeTask(taskName: string, handlerName: string) {
  const handler = taskHandlers[handlerName]
  if (!handler) {
    console.warn(`[Scheduler] No handler registered for: ${handlerName}`)
    return
  }

  try {
    await query(
      `UPDATE analytics.v3_scheduled_task SET last_status = 'running', updated_at = NOW() WHERE task_name = $1`,
      [taskName]
    )

    await handler()

    await query(
      `UPDATE analytics.v3_scheduled_task SET last_run_at = NOW(), last_status = 'success', last_error = NULL, updated_at = NOW() WHERE task_name = $1`,
      [taskName]
    )
    console.log(`[Scheduler] Task "${taskName}" completed successfully`)
  } catch (err: any) {
    await query(
      `UPDATE analytics.v3_scheduled_task SET last_run_at = NOW(), last_status = 'failed', last_error = $2, updated_at = NOW() WHERE task_name = $1`,
      [taskName, err.message]
    )
    console.error(`[Scheduler] Task "${taskName}" failed:`, err.message)
  }
}

export async function startScheduler() {
  const result = await query(
    `SELECT task_name, cron_expr, handler, is_enabled FROM analytics.v3_scheduled_task WHERE is_enabled = true`
  )

  for (const row of result.rows) {
    if (!cron.validate(row.cron_expr)) {
      console.warn(`[Scheduler] Invalid cron expression for "${row.task_name}": ${row.cron_expr}`)
      continue
    }

    const task = cron.schedule(row.cron_expr, () => {
      executeTask(row.task_name, row.handler)
    })

    registeredTasks.set(row.task_name, {
      name: row.task_name,
      cron: row.cron_expr,
      handler: taskHandlers[row.handler] || (async () => {}),
      task,
    })

    console.log(`[Scheduler] Registered task "${row.task_name}" with cron: ${row.cron_expr}`)
  }

  console.log(`[Scheduler] Started with ${registeredTasks.size} tasks`)
}

export async function stopScheduler() {
  for (const [, task] of registeredTasks) {
    task.task?.stop()
  }
  registeredTasks.clear()
  console.log('[Scheduler] Stopped')
}

export async function reloadScheduler() {
  await stopScheduler()
  await startScheduler()
}

export async function triggerTaskManually(taskName: string) {
  const result = await query(
    `SELECT task_name, handler FROM analytics.v3_scheduled_task WHERE task_name = $1`,
    [taskName]
  )
  if (result.rows.length === 0) {
    throw new Error(`Task not found: ${taskName}`)
  }
  const row = result.rows[0]
  await executeTask(row.task_name, row.handler)
}

export function getRegisteredTaskCount() {
  return registeredTasks.size
}
