import { NextResponse } from "next/server"

import { assertAdminSession } from "@/lib/auth-server"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { prisma } from "@/lib/prisma"
import {
  computeNextRunAt,
  sanitizeRecipients,
  sanitizeReportKeys,
  serializeSchedule,
} from "@/server/report-schedule-service"

export const runtime = "nodejs"

export async function GET() {
  const session = await assertAdminSession()
  if (!session) {
    return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
  }
  const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID

  const [schedules, runs] = await Promise.all([
    prisma.reportExportSchedule.findMany({
      where: { tenantId },
      orderBy: { createdAt: "desc" },
    }),
    prisma.reportExportRun.findMany({
      where: { tenantId },
      orderBy: { startedAt: "desc" },
      take: 50,
    }),
  ])
  const runBySchedule = runs.reduce<Record<string, typeof runs>>((acc, run) => {
    acc[run.scheduleId] = acc[run.scheduleId] ? [...acc[run.scheduleId], run] : [run]
    return acc
  }, {})

  return NextResponse.json({
    items: schedules.map((schedule) =>
      serializeSchedule(
        {
          ...schedule,
          reportKeys: sanitizeReportKeys((schedule.reportKeys as string[] | null) ?? []),
          recipients: (schedule.recipients as string[] | null) ?? [],
        },
        runBySchedule[schedule.id] ?? []
      )
    ),
  })
}

export async function POST(request: Request) {
  const session = await assertAdminSession()
  if (!session) {
    return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
  }
  const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
  const payload = (await request.json().catch(() => null)) as
    | {
        name?: string
        reportKeys?: string[]
        range?: string
        companyId?: string | null
        companyName?: string | null
        frequency?: "daily" | "weekly" | "monthly"
        dayOfWeek?: number | null
        dayOfMonth?: number | null
        time?: string
        timezone?: string
        recipients?: string[]
        format?: string
      }
    | null

  if (!payload) {
    return NextResponse.json({ error: "Payload inválido" }, { status: 400 })
  }

  const name = payload.name?.trim()
  if (!name) {
    return NextResponse.json({ error: "Informe um nome para o agendamento." }, { status: 400 })
  }

  const reportKeys = sanitizeReportKeys(payload.reportKeys ?? [])
  if (reportKeys.length === 0) {
    return NextResponse.json({ error: "Selecione ao menos um relatório." }, { status: 400 })
  }

  const recipients = sanitizeRecipients(payload.recipients ?? [])
  if (recipients.length === 0) {
    return NextResponse.json({ error: "Informe ao menos um destinatário válido." }, { status: 400 })
  }

  const frequency = (payload.frequency ?? "weekly").toLowerCase() as "daily" | "weekly" | "monthly"
  const { hour, minute } = parseTime(payload.time ?? "08:00")
  const timezone = payload.timezone ?? "America/Sao_Paulo"

  const nextRunAt = computeNextRunAt(
    {
      frequency,
      dayOfWeek: payload.dayOfWeek,
      dayOfMonth: payload.dayOfMonth,
      hour,
      minute,
      timezone,
    },
    new Date()
  )

  const schedule = await prisma.reportExportSchedule.create({
    data: {
      tenantId,
      name,
      reportKeys,
      range: payload.range ?? "30d",
      companyId: payload.companyId ?? null,
      companyName: payload.companyName ?? null,
      format: payload.format ?? "xlsx",
      frequency,
      dayOfWeek: payload.dayOfWeek ?? null,
      dayOfMonth: payload.dayOfMonth ?? null,
      hour,
      minute,
      timezone,
      recipients,
      status: "ACTIVE",
      createdBy: session.user.id,
      nextRunAt,
    },
  })

  return NextResponse.json({
    item: serializeSchedule(
      { ...schedule, reportKeys, recipients },
      []
    ),
  })
}

function parseTime(value: string) {
  const match = value.match(/^(\d{1,2}):(\d{1,2})$/)
  if (!match) return { hour: 8, minute: 0 }
  const hour = Math.min(23, Math.max(0, Number(match[1])))
  const minute = Math.min(59, Math.max(0, Number(match[2])))
  return { hour, minute }
}
