import { importSpielplan } from '../utils/spielplan-import.js'
import { importLeagueTables } from '../utils/spielklassen-tables-import.js'
import { info as loggerInfo, error as loggerError } from '../utils/logger.js'

const TIME_ZONE = 'Europe/Berlin'
const RUN_HOUR = 7
const RUN_MINUTE = 0
const MAX_TIMEOUT = 2_147_483_647

let timer = null
let running = false

function getTimeParts(date) {
  const parts = new Intl.DateTimeFormat('en-CA', {
    timeZone: TIME_ZONE,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  }).formatToParts(date)

  return Object.fromEntries(parts.map((part) => [part.type, part.value]))
}

function getTimeZoneOffset(date) {
  const parts = getTimeParts(date)
  const zonedAsUtc = Date.UTC(
    Number(parts.year),
    Number(parts.month) - 1,
    Number(parts.day),
    Number(parts.hour),
    Number(parts.minute),
    Number(parts.second)
  )

  return zonedAsUtc - date.getTime()
}

function zonedDateToUtc(year, month, day, hour, minute) {
  const utcGuess = new Date(Date.UTC(year, month - 1, day, hour, minute, 0))
  const offset = getTimeZoneOffset(utcGuess)
  return new Date(utcGuess.getTime() - offset)
}

function nextRunAt(now = new Date()) {
  const parts = getTimeParts(now)
  let year = Number(parts.year)
  let month = Number(parts.month)
  let day = Number(parts.day)
  let candidate = zonedDateToUtc(year, month, day, RUN_HOUR, RUN_MINUTE)

  if (candidate <= now) {
    const nextDay = zonedDateToUtc(year, month, day + 1, 12, 0)
    const nextParts = getTimeParts(nextDay)
    year = Number(nextParts.year)
    month = Number(nextParts.month)
    day = Number(nextParts.day)
    candidate = zonedDateToUtc(year, month, day, RUN_HOUR, RUN_MINUTE)
  }

  return candidate
}

async function runImport(reason) {
  if (running) return

  running = true
  try {
    const spielplan = await importSpielplan()
    loggerInfo(`[spielplan-import] ${reason}: ${spielplan.matchCount} Spiele importiert`, { range: `${spielplan.source.season.dateStart} - ${spielplan.source.season.dateEnd}` })

    try {
      const tables = await importLeagueTables()
      loggerInfo(`[spielplan-import] ${reason}: ${tables.importedCount}/${tables.teamCount} Tabellen importiert`, {
        season: tables.seasonSlug,
        outputFile: tables.outputFile,
        errors: tables.errorCount
      })
    } catch (error) {
      loggerError('[spielplan-import] Tabellen-Import fehlgeschlagen:', { error })
    }
  } catch (error) {
    loggerError('[spielplan-import] Import fehlgeschlagen:', { error })
  } finally {
    running = false
  }
}

function scheduleNext() {
  const runAt = nextRunAt()
  const delay = Math.min(Math.max(runAt.getTime() - Date.now(), 1_000), MAX_TIMEOUT)

  timer = setTimeout(async () => {
    await runImport('taeglicher Lauf')
    scheduleNext()
  }, delay)

  timer.unref?.()
  loggerInfo('[spielplan-import] Naechster Lauf', { runAt: runAt.toISOString(), tz: TIME_ZONE, time: `${String(RUN_HOUR).padStart(2, '0')}:${String(RUN_MINUTE).padStart(2, '0')}` })
}

export default defineNitroPlugin((nitroApp) => {
  if (process.env.SPIELPLAN_IMPORT_DISABLED === 'true') {
    loggerInfo('[spielplan-import] Scheduler deaktiviert')
    return
  }

  scheduleNext()

  if (process.env.SPIELPLAN_IMPORT_RUN_ON_START === 'true') {
    runImport('Startlauf')
  }

  nitroApp.hooks.hookOnce('close', () => {
    if (timer) clearTimeout(timer)
  })
})
