// reimport.ts tests (QVS-P5, KAR-974): DB-wired load/apply/candidates/
// separate-comparison-stream orchestration. `loadQafSourceRows` is mocked
// (controlled source rows, same pattern as creation.test.ts) so
// `mapAndFingerprint`/`computeSyncDelta` run for REAL against deterministic
// fixtures; `buildQafValueStreamPreview`/`createValueStreamFromQaf` are
// mocked too — their OWN behaviour is already covered by preview.test.ts/
// creation.test.ts, this file only verifies reimport.ts's OWN orchestration
// (which table rows it reads/writes, in what order, with what payload).

import { describe, it, expect, vi, beforeEach } from 'vitest'
import type { QafSourceRows } from '../qaf-source'
import { buildQafRow } from './fixtures'

const { loadQafSourceRowsMock } = vi.hoisted(() => ({ loadQafSourceRowsMock: vi.fn() }))
vi.mock('../qaf-source', async (importOriginal) => {
  const actual = await importOriginal<typeof import('../qaf-source')>()
  return { ...actual, loadQafSourceRows: loadQafSourceRowsMock }
})

const { buildQafValueStreamPreviewMock } = vi.hoisted(() => ({ buildQafValueStreamPreviewMock: vi.fn() }))
vi.mock('../preview', () => ({ buildQafValueStreamPreview: buildQafValueStreamPreviewMock }))

const { createValueStreamFromQafMock } = vi.hoisted(() => ({ createValueStreamFromQafMock: vi.fn() }))
vi.mock('../creation', () => ({ createValueStreamFromQaf: createValueStreamFromQafMock }))

vi.mock('@/lib/logger', () => ({ logger: { warn: vi.fn(), info: vi.fn(), error: vi.fn(), debug: vi.fn() } }))

import { loadValueStreamSyncDelta, applyValueStreamSyncSelection, listReimportSourceCandidates, createComparisonValueStreamFromSync } from '../reimport'
import { mapAndFingerprint } from '../qaf-source'

interface QueryResult {
  data: unknown
  error?: unknown
}

/**
 * Generic chainable Supabase mock: every builder method (select/update/eq/
 * order/limit) returns an equally-chainable object carrying the SAME
 * queued result, and the object is itself `then`-able so `await` resolves
 * correctly regardless of which method the real code happens to terminate
 * the chain on (`.maybeSingle()` vs a bare `.eq()`/`.limit()`). One FIFO
 * queue per table name — `.from(table)` dequeues the next configured
 * response, so a table queried twice in one test (once to load, once to
 * update) is configured as a 2-entry array in call order.
 */
function makeSupabase(queues: Record<string, QueryResult[]>) {
  const remaining: Record<string, QueryResult[]> = Object.fromEntries(Object.entries(queues).map(([k, v]) => [k, [...v]]))
  function chainable(result: QueryResult): unknown {
    const obj = {
      select: () => chainable(result),
      update: () => chainable(result),
      eq: () => chainable(result),
      order: () => chainable(result),
      limit: () => chainable(result),
      maybeSingle: () => Promise.resolve(result),
      single: () => Promise.resolve(result),
      then: (onFulfilled: (r: QueryResult) => unknown, onRejected?: (e: unknown) => unknown) => Promise.resolve(result).then(onFulfilled, onRejected),
    }
    return obj
  }
  return {
    from: vi.fn((table: string) => {
      const queue = remaining[table]
      if (!queue || queue.length === 0) throw new Error(`reimport.test.ts mock: no queued response left for table "${table}"`)
      return chainable(queue.shift()!)
    }),
  }
}

const SOURCE_ROWS: QafSourceRows = {
  qafFile: {
    id: 'qaf-file-new',
    projectId: 'project-1',
    fileHash: 'hash-new',
    originalFileName: 'revision-2.xlsx',
    parserVersion: 'p2',
    fileLevelContext: { plannedCapacityPartsPerYear: null, lotSizeParts: null },
  },
  rows: [buildQafRow({ prozessbezeichnung: 'Schweißen', zykluszeit: 47 }), buildQafRow({ prozessbezeichnung: 'Montage', zykluszeit: 30 })],
  stepIds: ['step-new-0', 'step-new-1'],
}

const SNAPSHOT_SOURCE_ROWS: QafSourceRows = {
  qafFile: { ...SOURCE_ROWS.qafFile, id: 'qaf-file-orig', fileHash: 'hash-orig' },
  rows: [buildQafRow({ prozessbezeichnung: 'Schweißen', zykluszeit: 42 }), buildQafRow({ prozessbezeichnung: 'Montage', zykluszeit: 30 })],
  stepIds: ['step-orig-0', 'step-orig-1'],
}

function snapshotNodesFixture() {
  return mapAndFingerprint(SNAPSHOT_SOURCE_ROWS).mapped.nodes
}

const VSM_ROW_BASE = { id: 'vsm-1', project_id: 'project-1', title: 'Lieferant X · QAF-Wertstrom', connections: [], updated_at: '2026-07-01T00:00:00Z' }
const IMPORT_ROW_BASE = {
  id: 'import-1',
  qaf_file_id: 'qaf-file-orig',
  project_id: 'project-1',
  source_file_name: 'orig.xlsx',
  file_hash: 'hash-orig',
  parser_version: 'p1',
  mapping_version: 'qvs-1',
  engine_context: { previewToken: 'old-token' },
}

beforeEach(() => {
  loadQafSourceRowsMock.mockReset()
  buildQafValueStreamPreviewMock.mockReset()
  createValueStreamFromQafMock.mockReset()
  loadQafSourceRowsMock.mockResolvedValue(SOURCE_ROWS)
})

describe('loadValueStreamSyncDelta', () => {
  it('loads live nodes + snapshot + a fresh source re-map and returns a computed delta', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })

    const outcome = await loadValueStreamSyncDelta(supabase as never, 'vsm-1')
    expect(outcome.ok).toBe(true)
    if (!outcome.ok) throw new Error('expected ok')
    // Defaults to the import row's OWN qaf_file_id (no override passed) —
    // `loadQafSourceRowsMock` still resolves the SOURCE_ROWS fixture
    // regardless of which id it was called with, see the dedicated
    // "defaults sourceQafFileId..." test below for the call-argument check.
    expect(outcome.data.sourceQafFileId).toBe('qaf-file-orig')
    expect(outcome.data.importId).toBe('import-1')
    const schweissen = outcome.data.delta.steps.find((s) => s.name === 'Schweißen')!
    expect(schweissen.status).toBe('SOURCE_CHANGED') // 42 -> 47
    expect(outcome.data.delta.steps.find((s) => s.name === 'Montage')!.status).toBe('UNCHANGED')
  })

  it('defaults sourceQafFileId to the import row\'s own qaf_file_id when not given', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })

    await loadValueStreamSyncDelta(supabase as never, 'vsm-1')
    expect(loadQafSourceRowsMock).toHaveBeenCalledWith(supabase, 'qaf-file-orig')
  })

  it('honours an explicit sourceQafFileId override', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })

    await loadValueStreamSyncDelta(supabase as never, 'vsm-1', { sourceQafFileId: 'qaf-file-explicit' })
    expect(loadQafSourceRowsMock).toHaveBeenCalledWith(supabase, 'qaf-file-explicit')
  })

  it('returns {ok:false, error:"not_found"} when the value stream is not found/visible (RLS 0-row)', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: null }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: null } }],
    })
    expect(await loadValueStreamSyncDelta(supabase as never, 'vsm-missing')).toEqual({ ok: false, error: 'not_found' })
  })

  it('returns {ok:false, error:"not_found"} when the value stream has no import record at all (never QAF-imported)', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: [] } }],
      value_stream_imports: [{ data: null }],
    })
    expect(await loadValueStreamSyncDelta(supabase as never, 'vsm-1')).toEqual({ ok: false, error: 'not_found' })
  })

  it('returns {ok:false, error:"not_found"} when the (resolved) source qaf_file itself is gone/not visible', async () => {
    loadQafSourceRowsMock.mockResolvedValue(null)
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })
    expect(await loadValueStreamSyncDelta(supabase as never, 'vsm-1')).toEqual({ ok: false, error: 'not_found' })
  })

  // Review-Fix (critical, KAR-974 adversarial review): sourceQafFileId was
  // never checked against the target value stream's own project — a caller
  // with several projects could point a reimport at a qaf_file from a
  // DIFFERENT project they also own (owner-scoped, not project-scoped RLS).
  it('returns {ok:false, error:"not_found"} when the resolved source qaf_file belongs to a DIFFERENT project than the value stream (fail-closed, no cross-project mixing)', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, project_id: 'project-1', nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, project_id: 'project-1', import_snapshot: { nodes: liveNodes } } }],
    })
    // SOURCE_ROWS (the module-level fixture loadQafSourceRowsMock resolves to
    // by default) carries qafFile.projectId: 'project-1' — override it to a
    // different project to simulate the cross-project source file.
    loadQafSourceRowsMock.mockResolvedValueOnce({ ...SOURCE_ROWS, qafFile: { ...SOURCE_ROWS.qafFile, projectId: 'project-2' } })

    const outcome = await loadValueStreamSyncDelta(supabase as never, 'vsm-1', { sourceQafFileId: 'qaf-file-foreign' })
    expect(outcome).toEqual({ ok: false, error: 'not_found' })
  })

  // Review-Fix (minor, KAR-974 adversarial review): a genuine query error
  // (transient/infra) used to collapse into the exact same `null` a 0-row
  // "not found" result produced — now distinguishable as `load_failed`.
  it('returns {ok:false, error:"load_failed"} — distinguishable from not_found — when the underlying value_stream_maps query itself errors', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: null, error: { message: 'connection reset', code: '57P01' } }],
      value_stream_imports: [{ data: IMPORT_ROW_BASE }],
    })
    expect(await loadValueStreamSyncDelta(supabase as never, 'vsm-1')).toEqual({ ok: false, error: 'load_failed' })
  })

  it('returns {ok:false, error:"load_failed"} when the underlying value_stream_imports query itself errors', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: VSM_ROW_BASE }],
      value_stream_imports: [{ data: null, error: { message: 'timeout', code: '57014' } }],
    })
    expect(await loadValueStreamSyncDelta(supabase as never, 'vsm-1')).toEqual({ ok: false, error: 'load_failed' })
  })
})

describe('applyValueStreamSyncSelection', () => {
  async function loadDeltaToken(supabase: unknown): Promise<string> {
    const outcome = await loadValueStreamSyncDelta(supabase as never, 'vsm-1')
    if (!outcome.ok) throw new Error(`expected ok, got error: ${outcome.error}`)
    return outcome.data.deltaToken
  }

  // Review-Fix (major, KAR-974 adversarial review): this test's own name
  // ("...persists value_stream_maps THEN value_stream_imports") previously
  // asserted only that BOTH tables were called at some point
  // (`toHaveBeenCalledWith` twice), never their RELATIVE order — a
  // regression that swapped the write order would have stayed green here
  // (verified live during the review: swapping the two update blocks left
  // this exact test passing). `supabase2.from.mock.calls` now asserts the
  // full, ordered call sequence directly.
  it('applies the plan and persists value_stream_maps THEN value_stream_imports (real call-order assertion)', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }, { data: { id: 'vsm-1' } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }, { data: { id: 'import-1' } }],
    })

    const deltaToken = await loadDeltaToken(supabase)
    // Re-arm the mock queues for the SECOND (apply-internal) load — the
    // production code recomputes state fresh rather than trusting a
    // caller-supplied delta, same discipline as creation.ts's previewToken.
    const supabase2 = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }, { data: { id: 'vsm-1' } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }, { data: { id: 'import-1' } }],
    })

    const outcome = await applyValueStreamSyncSelection(supabase2 as never, {
      valueStreamId: 'vsm-1',
      deltaToken,
      plan: { mode: 'all' },
    })

    expect(outcome.ok).toBe(true)
    if (!outcome.ok) throw new Error('expected ok')
    expect(outcome.result.summary.fieldsAdopted).toBe(1) // Schweißen cycleTimeSec 42 -> 47
    // Exact, ordered call sequence: load (maps, imports — Promise.all array
    // order) THEN the two writes in the Leitplanke-mandated order (maps
    // UPDATE before imports UPDATE).
    expect(supabase2.from.mock.calls.map((c) => c[0])).toEqual(['value_stream_maps', 'value_stream_imports', 'value_stream_maps', 'value_stream_imports'])
  })

  // Review-Fix (major, KAR-974 adversarial review): the "persistence order"
  // guarantee is only meaningful if a step-2 failure demonstrably leaves
  // step-1's write intact and step-2's write never observed as having
  // happened — asserted explicitly here, not just implied.
  it('on a value_stream_imports (step 2) failure: value_stream_maps IS written, value_stream_imports UPDATE is attempted but rejected — explicit partial-failure state', async () => {
    const liveNodes = snapshotNodesFixture()
    const loadSupabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })
    const deltaToken = await loadDeltaToken(loadSupabase)

    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }, { data: { id: 'vsm-1' } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }, { data: null, error: { message: 'connection reset', code: '57P01' } }],
    })

    const outcome = await applyValueStreamSyncSelection(supabase as never, { valueStreamId: 'vsm-1', deltaToken, plan: { mode: 'all' } })

    expect(outcome).toEqual({ ok: false, error: { code: 'db_error', message: 'connection reset' } })
    // The maps UPDATE's queued response WAS consumed (2nd 'value_stream_maps'
    // queue entry) — proving the write happened — before the imports UPDATE
    // was even attempted (3rd/4th call in the sequence).
    expect(supabase.from.mock.calls.map((c) => c[0])).toEqual(['value_stream_maps', 'value_stream_imports', 'value_stream_maps', 'value_stream_imports'])
  })

  it('rejects with stale_delta when the supplied token does not match a fresh recompute', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })

    const outcome = await applyValueStreamSyncSelection(supabase as never, {
      valueStreamId: 'vsm-1',
      deltaToken: 'a-token-that-cannot-possibly-match',
      plan: { mode: 'all' },
    })
    expect(outcome).toEqual({ ok: false, error: { code: 'stale_delta' } })
  })

  it('returns not_found when the value stream itself is not found/visible', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: null }],
      value_stream_imports: [{ data: null }],
    })
    const outcome = await applyValueStreamSyncSelection(supabase as never, { valueStreamId: 'vsm-x', deltaToken: 'irrelevant', plan: { mode: 'none' } })
    expect(outcome).toEqual({ ok: false, error: { code: 'not_found' } })
  })

  // Review-Fix (critical, KAR-974 adversarial review) — apply-path half of
  // the cross-project guard (loadValueStreamSyncDelta's test above covers
  // the delta/GET path; both funnel through the same loadSyncState).
  it('returns not_found (fail-closed) when the resolved source qaf_file belongs to a DIFFERENT project than the value stream', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, project_id: 'project-1', nodes: liveNodes } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, project_id: 'project-1', import_snapshot: { nodes: liveNodes } } }],
    })
    loadQafSourceRowsMock.mockResolvedValueOnce({ ...SOURCE_ROWS, qafFile: { ...SOURCE_ROWS.qafFile, projectId: 'project-2' } })

    const outcome = await applyValueStreamSyncSelection(supabase as never, {
      valueStreamId: 'vsm-1',
      sourceQafFileId: 'qaf-file-foreign',
      deltaToken: 'irrelevant-never-reached',
      plan: { mode: 'all' },
    })
    expect(outcome).toEqual({ ok: false, error: { code: 'not_found' } })
  })

  // Review-Fix (minor, KAR-974 adversarial review) — apply-path half of the
  // not_found/load_failed distinction: maps to the EXISTING db_error code
  // (already has a fitting "please retry" UI message), no new client-facing
  // code needed on this path.
  it('returns {code:"db_error"} (never not_found) when the underlying load itself errors (transient DB failure)', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: null, error: { message: 'connection reset', code: '57P01' } }],
      value_stream_imports: [{ data: IMPORT_ROW_BASE }],
    })
    const outcome = await applyValueStreamSyncSelection(supabase as never, { valueStreamId: 'vsm-1', deltaToken: 'irrelevant', plan: { mode: 'all' } })
    expect(outcome.ok).toBe(false)
    if (outcome.ok) throw new Error('expected rejection')
    expect(outcome.error.code).toBe('db_error')
  })

  it('surfaces db_error without crashing when the value_stream_maps update itself errors', async () => {
    const liveNodes = snapshotNodesFixture()
    const supabase = makeSupabase({
      value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }, { data: null, error: { message: 'connection reset' } }],
      value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
    })

    const deltaToken = await loadDeltaToken(
      makeSupabase({
        value_stream_maps: [{ data: { ...VSM_ROW_BASE, nodes: liveNodes } }],
        value_stream_imports: [{ data: { ...IMPORT_ROW_BASE, import_snapshot: { nodes: liveNodes } } }],
      }),
    )

    const outcome = await applyValueStreamSyncSelection(supabase as never, { valueStreamId: 'vsm-1', deltaToken, plan: { mode: 'all' } })
    expect(outcome).toEqual({ ok: false, error: { code: 'db_error', message: 'connection reset' } })
  })
})

describe('listReimportSourceCandidates', () => {
  it('lists other qaf_file rows in the same project, flagging the currently-recorded source', async () => {
    const supabase = makeSupabase({
      value_stream_maps: [{ data: VSM_ROW_BASE }],
      value_stream_imports: [{ data: IMPORT_ROW_BASE }],
      qaf_file: [
        {
          data: [
            { id: 'qaf-file-new', original_file_name: 'revision-2.xlsx', created_at: '2026-07-15T00:00:00Z' },
            { id: 'qaf-file-orig', original_file_name: 'orig.xlsx', created_at: '2026-06-01T00:00:00Z' },
          ],
        },
      ],
    })

    const candidates = await listReimportSourceCandidates(supabase as never, 'vsm-1')
    expect(candidates).toHaveLength(2)
    expect(candidates!.find((c) => c.qafFileId === 'qaf-file-orig')!.isCurrentSource).toBe(true)
    expect(candidates!.find((c) => c.qafFileId === 'qaf-file-new')!.isCurrentSource).toBe(false)
  })

  it('returns null when the value stream has no import record', async () => {
    const supabase = makeSupabase({ value_stream_maps: [{ data: VSM_ROW_BASE }], value_stream_imports: [{ data: null }] })
    expect(await listReimportSourceCandidates(supabase as never, 'vsm-1')).toBeNull()
  })
})

describe('createComparisonValueStreamFromSync', () => {
  it("builds a fresh preview of the chosen source and confirms it under '<original title> · Reimport <Datum>', reusing createValueStreamFromQaf as-is, with its own persistedTokenSuffix (never the bare previewToken)", async () => {
    const supabase = makeSupabase({ value_stream_maps: [{ data: { id: 'vsm-1', title: 'Lieferant X · QAF-Wertstrom' } }] })
    buildQafValueStreamPreviewMock.mockResolvedValue({ previewToken: 'fresh-token', qafFileId: 'qaf-file-new' })
    createValueStreamFromQafMock.mockResolvedValue({ ok: true, result: { valueStreamId: 'vsm-2', importId: 'import-2', idempotentHit: false } })

    const outcome = await createComparisonValueStreamFromSync(supabase as never, {
      valueStreamId: 'vsm-1',
      sourceQafFileId: 'qaf-file-new',
      now: new Date('2026-07-17T10:00:00Z'),
    })

    expect(outcome).toEqual({ ok: true, result: { valueStreamId: 'vsm-2', importId: 'import-2', idempotentHit: false } })
    expect(createValueStreamFromQafMock).toHaveBeenCalledWith(
      supabase,
      {
        qafFileId: 'qaf-file-new',
        previewToken: 'fresh-token',
        title: 'Lieferant X · QAF-Wertstrom · Reimport 17.07.2026',
      },
      undefined,
      { persistedTokenSuffix: 'reimport-comparison:vsm-1:2026-07-17' },
    )
  })

  // Review-Fix (critical, KAR-974 adversarial review): the previously
  // reachable collision — sourceQafFileId equal to the value stream's OWN
  // (default, unchanged) source qaf_file produces the SAME previewToken the
  // ORIGINAL import already persisted, so create_value_stream_from_qaf's
  // (project_id, previewToken) partial unique index would find the
  // ORIGINAL's row and report idempotent_hit: true pointing at the ORIGINAL
  // value stream — this is exactly the collision case the fix's
  // persistedTokenSuffix mechanism must prevent, and the ONE the previous
  // dialog test (qvs-reimport-dialog.test.tsx) never exercised (it always
  // mocked idempotentHit: false).
  it('always supplies its OWN comparison-scoped persistedTokenSuffix even when sourceQafFileId is the value stream\'s own (default) source — never collides with the original import\'s bare token', async () => {
    const supabase = makeSupabase({ value_stream_maps: [{ data: { id: 'vsm-1', title: 'Lieferant X · QAF-Wertstrom' } }] })
    // Same qaf_file_id / previewToken the ORIGINAL import of vsm-1 would have
    // persisted under — the "user never touched the source dropdown" case.
    buildQafValueStreamPreviewMock.mockResolvedValue({ previewToken: 'old-token', qafFileId: 'qaf-file-orig' })
    // Mocked here as the RPC reporting a genuine same-day resubmit collision
    // — this test's job is only to prove the CALL passes its own suffix
    // (never the bare 'old-token') and that idempotentHit passes through
    // unchanged for the caller (Action/dialog) to react to honestly.
    createValueStreamFromQafMock.mockResolvedValue({ ok: true, result: { valueStreamId: 'vsm-1', importId: 'import-1', idempotentHit: true } })

    const outcome = await createComparisonValueStreamFromSync(supabase as never, {
      valueStreamId: 'vsm-1',
      sourceQafFileId: 'qaf-file-orig',
      now: new Date('2026-07-17T10:00:00Z'),
    })

    expect(outcome).toEqual({ ok: true, result: { valueStreamId: 'vsm-1', importId: 'import-1', idempotentHit: true } })
    const [, , variantTagging, options] = createValueStreamFromQafMock.mock.calls[0] as [unknown, unknown, unknown, { persistedTokenSuffix?: string } | undefined]
    expect(variantTagging).toBeUndefined()
    expect(options?.persistedTokenSuffix).toBe('reimport-comparison:vsm-1:2026-07-17')
    expect(options?.persistedTokenSuffix).not.toBe('old-token')
  })

  it('returns null when the value stream itself is not found', async () => {
    const supabase = makeSupabase({ value_stream_maps: [{ data: null }] })
    expect(await createComparisonValueStreamFromSync(supabase as never, { valueStreamId: 'vsm-x', sourceQafFileId: 'qaf-file-new' })).toBeNull()
    expect(buildQafValueStreamPreviewMock).not.toHaveBeenCalled()
  })

  it('returns null when the chosen source qaf_file preview cannot be built (not found/not visible)', async () => {
    const supabase = makeSupabase({ value_stream_maps: [{ data: { id: 'vsm-1', title: 'X' } }] })
    buildQafValueStreamPreviewMock.mockResolvedValue(null)
    expect(await createComparisonValueStreamFromSync(supabase as never, { valueStreamId: 'vsm-1', sourceQafFileId: 'qaf-file-gone' })).toBeNull()
    expect(createValueStreamFromQafMock).not.toHaveBeenCalled()
  })
})
