import 'server-only'

import { NextResponse, type NextRequest } from 'next/server'
import { requireParticipant, type Guard } from '@/lib/api-guard'
import { publicOrigin } from '@/lib/app-url'
import { isMissingColumn } from '@/lib/db-compat'
import { canRequestServices } from '@/lib/domain/permissions'
import { createAdminClient } from '@/lib/supabase/admin'
import type { PermitRequestDraft, Trip } from '@/types/db'

/**
 * Buy More Permits drafts (2026-09-29 task §9.4): step 1 of the two-step
 * dialog saved before the customer leaves for Synchron's secure card page.
 * One pending draft per user per trip (partial unique index, migration 0047).
 */

export type DraftRouteContext =
  | { ok: true; guard: Extract<Guard, { ok: true }>; trip: Trip }
  | { ok: false; response: NextResponse }

/** Shared preamble of every permit-payment route: participant + may request + trip exists. */
export async function requirePermitRequester(tripId: string): Promise<DraftRouteContext> {
  const guard = await requireParticipant(tripId)
  if (!guard.ok) return guard
  if (!canRequestServices(guard.participant.role)) {
    return { ok: false, response: NextResponse.json({ error: 'Your role cannot order permits.' }, { status: 403 }) }
  }
  const { data } = await createAdminClient().from('trips').select('*').eq('id', tripId).single()
  const trip = (data ?? null) as Trip | null
  if (!trip) return { ok: false, response: NextResponse.json({ error: 'Trip not found.' }, { status: 404 }) }
  return { ok: true, guard, trip }
}

export async function loadOwnDraft(draftId: string, tripId: string, userId: string): Promise<
  { ok: true; draft: PermitRequestDraft } | { ok: false; response: NextResponse }
> {
  const { data } = await createAdminClient()
    .from('permit_request_drafts')
    .select('*')
    .eq('id', draftId)
    .eq('trip_id', tripId)
    .maybeSingle()
  const draft = (data ?? null) as PermitRequestDraft | null
  if (!draft) return { ok: false, response: NextResponse.json({ error: 'Draft not found.' }, { status: 404 }) }
  if (draft.user_id !== userId) return { ok: false, response: NextResponse.json({ error: 'Not your draft.' }, { status: 403 }) }
  return { ok: true, draft }
}

export async function updateDraft(
  draftId: string,
  patch: Partial<Pick<PermitRequestDraft, 'readiness_status' | 'status' | 'setup_reference'>>,
): Promise<PermitRequestDraft | null> {
  const admin = createAdminClient()
  let { data, error } = await admin.from('permit_request_drafts').update(patch).eq('id', draftId).select().single()
  if (error && 'setup_reference' in patch && isMissingColumn(error, 'setup_reference')) {
    // Migration 0048 not applied yet — keep the rest of the patch.
    const { setup_reference: _ignored, ...rest } = patch
    void _ignored
    ;({ data, error } = await admin.from('permit_request_drafts').update(rest).eq('id', draftId).select().single())
  }
  return (data ?? null) as PermitRequestDraft | null
}

/**
 * Where Synchron sends the customer back: the CD trip page reopens the dialog
 * from the draft. `setup` is appended when the reference is already known;
 * the hosted page may add it itself, and the draft row keeps a copy either way.
 */
export function permitPaymentReturnUrl(req: NextRequest, trip: Trip, draftId: string, setupReference?: string | null): string {
  const url = new URL(`/cd-trip-workspace/${encodeURIComponent(trip.ref_code)}`, publicOrigin(req))
  url.searchParams.set('draft', draftId)
  if (setupReference) url.searchParams.set('setup', setupReference)
  return url.toString()
}
