import { createError, getHeader, readBody, type H3Event } from "h3"

import {
  assertPersistedSourceSlug,
  persistedSourceSlugs,
  scrapeAndStoreSource,
  type PersistedSourceSlug,
  type SourceIngestResult
} from "~/server/utils/scrape-storage"

interface CronScrapeBody {
  sources?: string[]
  continueOnError?: boolean
}

interface CronScrapeFailure {
  source: string
  message: string
}

const getProvidedToken = (event: H3Event) => {
  const headerToken = getHeader(event, "x-cron-token")

  if (headerToken) {
    return headerToken.trim()
  }

  const authHeader = getHeader(event, "authorization")

  if (authHeader?.startsWith("Bearer ")) {
    return authHeader.slice("Bearer ".length).trim()
  }

  return ""
}

const assertCronToken = (event: H3Event) => {
  const expected = process.env.SCRAPE_CRON_TOKEN?.trim()

  if (!expected) {
    throw createError({
      statusCode: 503,
      statusMessage: "SCRAPE_CRON_TOKEN no configurado"
    })
  }

  const provided = getProvidedToken(event)

  if (!provided || provided !== expected) {
    throw createError({
      statusCode: 401,
      statusMessage: "Token de cron invalido"
    })
  }
}

export default defineEventHandler(async (event) => {
  assertCronToken(event)

  const startedAt = new Date()
  const parsedBody = (await readBody<CronScrapeBody>(event).catch(() => undefined)) ?? {}
  const continueOnError = parsedBody.continueOnError ?? true

  const requestedSources = Array.isArray(parsedBody.sources) && parsedBody.sources.length
    ? parsedBody.sources
    : persistedSourceSlugs

  const uniqueRequested = [...new Set(requestedSources)]
  const validSources: PersistedSourceSlug[] = []
  const failures: CronScrapeFailure[] = []

  for (const source of uniqueRequested) {
    try {
      validSources.push(assertPersistedSourceSlug(source))
    } catch {
      failures.push({
        source,
        message: "Fuente no soportada"
      })
    }
  }

  const ok: SourceIngestResult[] = []

  for (const source of validSources) {
    try {
      const result = await scrapeAndStoreSource(source)
      ok.push(result)
    } catch (error) {
      failures.push({
        source,
        message: error instanceof Error ? error.message : "Fallo desconocido"
      })

      if (!continueOnError) {
        break
      }
    }
  }

  return {
    startedAt: startedAt.toISOString(),
    finishedAt: new Date().toISOString(),
    requestedSources: uniqueRequested,
    continueOnError,
    ok,
    failed: failures
  }
})
