import type { Prisma, PrismaClient } from '@prisma/client'
import { signExternalLunchToken } from '@/lib/external-lunch-token'
import { getBaseUrl, sendExternalDishInviteEmail } from '@/lib/email'

type PrismaLike = PrismaClient | Prisma.TransactionClient

export type InvitableExternal = {
  id: string
  name: string
  email: string | null
}

export type InviteLunchEvent = {
  eventAt: Date | null
  venue: string | null
  notes: string | null
  changeCutoffHours: number
}

/**
 * Build the public, tokenized dish-pick URL for an external attendee.
 * The token is a stateless HMAC signature (see external-lunch-token) carrying the
 * externalId; `exp` is generous (event day + 1, or 30 days when no event date)
 * so the link outlives the change deadline, which is enforced separately at write.
 */
export function buildExternalPickUrl(externalId: string, eventAt: Date | null): string {
  const exp = eventAt
    ? Math.floor(eventAt.getTime() / 1000) + 86_400
    : Math.floor(Date.now() / 1000) + 30 * 86_400
  const token = signExternalLunchToken({ externalId, exp })
  return `${getBaseUrl()}/lunch/pick/${token}`
}

/**
 * Send (or resend) the dish-selection invite to one external attendee and stamp
 * `inviteSentAt`. Throws if the external has no email or the email send fails;
 * callers that must not fail (e.g. createExternal) wrap this in try/catch.
 */
export async function sendExternalDishInvite(
  prisma: PrismaLike,
  external: InvitableExternal,
  event: InviteLunchEvent,
): Promise<void> {
  if (!external.email) throw new Error('External attendee has no email address')
  const changeDeadline = event.eventAt
    ? new Date(event.eventAt.getTime() - event.changeCutoffHours * 3_600_000)
    : null
  await sendExternalDishInviteEmail({
    to: external.email,
    name: external.name,
    eventAt: event.eventAt,
    venue: event.venue,
    notes: event.notes,
    changeDeadline,
    pickUrl: buildExternalPickUrl(external.id, event.eventAt),
  })
  await prisma.externalAttendee.update({
    where: { id: external.id },
    data: { inviteSentAt: new Date() },
  })
}
