import 'server-only'

import { createAdminClient } from '@/lib/supabase/admin'
import { emailPattern } from '@/lib/like'
import { isMissingColumn } from '@/lib/db-compat'
import { evaluateParticipantRulesById } from '@/lib/data/auto-participants'

/**
 * Claiming historical trips (2026-09-14).
 *
 * A historical import creates participant rows with status `imported`: the
 * person is on the trip, but the row grants no access
 * (`src/lib/domain/participants.ts`). Nash: "if we have this email in our
 * db so we can show him old data" — after the person has VERIFIED that
 * email. This is the step that turns those rows live.
 *
 * Call it from the email-verification flow, or from an admin action, with
 * the verified address. It never runs on plain sign-in: the .env logins do
 * not verify email, and a historical order must not open to whoever types
 * a matching address (article §33).
 *
 * Returns the trip ids that became visible. Idempotent.
 */
export async function claimImportedTrips(params: {
  userId: string
  email: string
  method: 'email_verified' | 'admin'
  actorLabel: string
  /** Source ids of the same person (e.g. `user:2378`), so a row imported under an older address still connects (2026-09-25). */
  sourceRecordIds?: string[]
}): Promise<{ tripIds: string[] }> {
  const admin = createAdminClient()
  const now = new Date().toISOString()
  const patch = { status: 'active', user_id: params.userId, claimed_at: now, claim_method: params.method }
  const byEmail = await admin.from('trip_participants').update(patch).eq('status', 'imported').ilike('email', emailPattern(params.email)).select('id, trip_id, role')
  let error = byEmail.error
  let rowsRaw = byEmail.data ?? []
  if (!error && params.sourceRecordIds?.length) {
    const bySource = await admin.from('trip_participants').update(patch).eq('status', 'imported').in('source_record_id', params.sourceRecordIds).select('id, trip_id, role')
    error = bySource.error
    rowsRaw = [...rowsRaw, ...(bySource.data ?? [])]
  }
  const data = rowsRaw
  if (error) {
    // Migration 0017 not applied → nothing was ever imported; nothing to claim.
    if (isMissingColumn(error, 'claimed_at', 'claim_method') || /invalid input value for enum/i.test(error.message)) {
      return { tripIds: [] }
    }
    throw new Error(`claim imported trips: ${error.message}`)
  }
  const rows = (data ?? []) as Array<{ id: string; trip_id: string; role: string }>
  if (rows.length === 0) return { tripIds: [] }
  await admin.from('trip_events').insert(
    rows.map((r) => ({
      trip_id: r.trip_id,
      actor_id: params.userId,
      actor_label: params.actorLabel,
      action: 'historical_trip_claimed',
      detail: { participant_id: r.id, role: r.role, method: params.method },
    })),
  )
  // Auto-Participants (2026-09-30, decision D10): a claimed trip brings the
  // person's team only when the trip was imported on or after the rule.
  for (const r of rows) {
    await evaluateParticipantRulesById({ tripId: r.trip_id, participantId: r.id, trigger: 'claim', session: null })
  }
  return { tripIds: [...new Set(rows.map((r) => r.trip_id))] }
}
