// Optimistic concurrency control via If-Match / updated_at.
//
// Mo2 finding P2-7: parallel writes overwrite each other ("Last Saved Wins").
// Fix: client reads the row's `updated_at`, sends it back as
// `If-Match: <iso-timestamp>` (or quoted ETag form) on PATCH/PUT/DELETE.
// Server compares against current `updated_at` and returns 409 if drift.
//
// Usage in route handler:
//
//   const expected = readIfMatch(req)
//   const { data: existing } = await supabase.from('assignments')
//     .select('updated_at').eq('id', id).single()
//   const guard = guardIfMatch(expected, existing?.updated_at)
//   if (guard) return guard
//
// Why If-Match (RFC 7232) and not a custom header:
//   - Browsers preserve it across redirects sensibly.
//   - Standard semantics: 412 Precondition Failed is the correct status,
//     but we use 409 here because consumers already understand 409 as
//     "retry-with-fresh-state". 412 is acceptable too.

import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'

const IF_MATCH_HEADER = 'if-match'

export function readIfMatch(request: NextRequest | Request): string | null {
  const raw = request.headers.get(IF_MATCH_HEADER)?.trim()
  if (!raw) return null
  // Strip quoted ETag form: "2026-05-08T01:23:45.000Z" -> 2026-05-08T01:23:45.000Z
  const m = raw.match(/^"(.+)"$/)
  return m ? m[1] : raw
}

export function guardIfMatch(
  expected: string | null,
  current: string | null | undefined,
): NextResponse | null {
  // No If-Match sent -> behave like before (last-write-wins). Documented
  // as a deliberate opt-in; clients that pass If-Match get strong
  // concurrency, clients that don't pass it accept the old behaviour.
  if (!expected) return null
  if (!current) {
    return NextResponse.json(
      { error: 'precondition_required', message: 'Resource has no updated_at to compare.' },
      { status: 412 },
    )
  }

  // Normalize both sides — Postgres timestamptz often serializes with
  // microsecond precision, JSON-stringify with millisecond. Compare
  // truncated to seconds for resilience.
  const norm = (s: string) => s.replace(/\.\d+/, '').replace(/[^\dTZ:.+\-]/g, '')
  if (norm(expected) !== norm(current)) {
    return NextResponse.json(
      {
        error: 'conflict',
        message: 'The resource has been modified by another user. Reload and retry.',
        current_updated_at: current,
      },
      { status: 409 },
    )
  }

  return null
}
