import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { createAdminClient } from '@/lib/supabase/admin'
import { requireParticipant } from '@/lib/api-guard'
import { isMissingColumn } from '@/lib/db-compat'
import { logTripEvent } from '@/lib/audit'

/**
 * "Let broker and dispatch see my questions and answers — yes or no."
 *
 * Per trip, per user (2026-09-07). Nash: "maybe I don't want the broker to
 * know that I'm asking these questions… maybe he's not going to look
 * knowledgeable enough, and he doesn't want others to see what kind of
 * questions he's asking." Applies to every role, not just the driver: "I think
 * this should be across the entire platform."
 *
 * Turning sharing OFF asks whether to hide the earlier questions too
 * (`hide_past`); by itself it only affects messages sent from now on.
 */

const schema = z.object({
  share: z.boolean(),
  /** Only meaningful when turning sharing off. */
  hide_past: z.boolean().optional().default(false),
})

export async function POST(req: NextRequest, ctx: { params: Promise<{ id: string }> }) {
  const { id: tripId } = await ctx.params
  const guard = await requireParticipant(tripId)
  if (!guard.ok) return guard.response
  const { user, participant } = guard

  const parsed = schema.safeParse(await req.json().catch(() => ({})))
  if (!parsed.success) return NextResponse.json({ error: 'Invalid request.' }, { status: 400 })
  const { share, hide_past } = parsed.data

  const admin = createAdminClient()

  const { error: prefError } = await admin
    .from('trip_participants')
    .update({ share_chat: share })
    .eq('id', participant.id)

  if (isMissingColumn(prefError, 'share_chat')) {
    return NextResponse.json(
      { error: 'Chat privacy needs database migration 0010.' },
      { status: 503 },
    )
  }
  if (prefError) {
    return NextResponse.json({ error: 'Could not save your choice.' }, { status: 500 })
  }

  let hidden = 0
  if (!share && hide_past) {
    hidden = await hidePastMessages(tripId, user.id)
  }
  // Turning sharing back ON deliberately affects FUTURE messages only.
  // Un-hiding what the user explicitly chose to hide would expose it to their
  // broker and dispatcher without them asking for that — the opposite of the
  // point of this feature. Nash asked to be asked before hiding; nothing in
  // the meeting asks for automatic un-hiding.

  await logTripEvent({
    tripId,
    actorId: user.id,
    actorLabel: participant.name || user.email || 'participant',
    action: 'chat_privacy_changed',
    detail: { share, hide_past: !share && hide_past, messages_hidden: hidden },
  })

  return NextResponse.json({ ok: true, share, hidden })
}

/**
 * Hide this user's existing questions on the trip, and the agent's answers to
 * them ("no others will see the questions AND answers").
 *
 * An answer is matched by its explicit `answer_to_message_id`. Messages
 * written before that column existed fall back to adjacency — the chat POST
 * writes question and answer together, in order. The fallback is deliberately
 * conservative: it only claims the immediately-following row, so under
 * concurrency it under-hides rather than ever hiding someone else's answer.
 */
async function hidePastMessages(tripId: string, userId: string): Promise<number> {
  const admin = createAdminClient()
  const { data } = await admin
    .from('chat_messages')
    .select('id, user_id, is_ai, answer_to_message_id, created_at')
    .eq('trip_id', tripId)
    .order('created_at')

  const rows = (data ?? []) as Array<{
    id: string
    user_id: string | null
    is_ai: boolean
    answer_to_message_id: string | null
  }>

  const mine = new Set(rows.filter((r) => !r.is_ai && r.user_id === userId).map((r) => r.id))
  const toHide = new Set(mine)

  for (let i = 0; i < rows.length; i++) {
    const row = rows[i]
    if (!row.is_ai) continue
    if (row.answer_to_message_id) {
      // Authoritative.
      if (mine.has(row.answer_to_message_id)) toHide.add(row.id)
      continue
    }
    // Historical row with no link — pair only with an immediately preceding
    // question of this user's.
    const prev = rows[i - 1]
    if (prev && !prev.is_ai && mine.has(prev.id)) toHide.add(row.id)
  }

  if (toHide.size === 0) return 0
  await admin
    .from('chat_messages')
    .update({ is_private: true, private_for_user_id: userId })
    .in('id', [...toHide])
  return toHide.size
}
