import { describe, expect, it } from 'vitest'
import {
  createMemoryUploadStore,
  finalizeUpload,
  FinalizeNotFoundError,
  type MemoryUploadStoreState,
} from '../src/uploads/finalize-upload'

function seedStore(overrides?: Partial<MemoryUploadStoreState>) {
  const parents = new Map<string, string>([
    ['a:parent-a1', 'actor-a'],
    ['b:parent-b1', 'actor-a'],
    ['a:foreign-a', 'victim'],
    ['b:foreign-b', 'victim'],
  ])
  const pending = new Map<string, string>([
    ['pending-a', 'actor-a'],
    ['pending-b', 'actor-b'],
  ])
  return createMemoryUploadStore({ parents, pending, bindings: new Map(), ...overrides })
}

describe('uploads host finalize fixture (Gate-4 authz wiring — NOT module conformance)', () => {
  it('A1: both parentType branches re-check ownership (foreign owner on either → 404)', () => {
    const storeA = seedStore()
    expect(() =>
      finalizeUpload(storeA, {
        actor: 'actor-a',
        parentType: 'a',
        parentId: 'foreign-a',
        uploadKey: 'pending-a',
      }),
    ).toThrow(FinalizeNotFoundError)

    const storeB = seedStore()
    expect(() =>
      finalizeUpload(storeB, {
        actor: 'actor-a',
        parentType: 'b',
        parentId: 'foreign-b',
        uploadKey: 'pending-a',
      }),
    ).toThrow(FinalizeNotFoundError)
  })

  it('A3: adoption filters on actor — actor-B cannot finalize actor-A pending upload', () => {
    const store = seedStore()
    expect(() =>
      finalizeUpload(store, {
        actor: 'actor-b',
        parentType: 'a',
        parentId: 'parent-a1',
        uploadKey: 'pending-a',
      }),
    ).toThrow(FinalizeNotFoundError)
  })

  it('A4: authz runs before store write — denied finalize leaves store unmutated', () => {
    const bindings = new Map()
    const store = createMemoryUploadStore({
      parents: new Map([['a:parent-a1', 'actor-a']]),
      pending: new Map([['pending-a', 'actor-a']]),
      bindings,
    })

    expect(() =>
      finalizeUpload(store, {
        actor: 'actor-b',
        parentType: 'a',
        parentId: 'parent-a1',
        uploadKey: 'pending-a',
      }),
    ).toThrow(FinalizeNotFoundError)
    expect(bindings.size).toBe(0)
  })

  it('A5: absent parent and foreign-owner parent both return uniform 404', () => {
    const store = seedStore()
    const absent = () =>
      finalizeUpload(store, {
        actor: 'actor-a',
        parentType: 'a',
        parentId: 'missing',
        uploadKey: 'pending-a',
      })
    const foreign = () =>
      finalizeUpload(store, {
        actor: 'actor-a',
        parentType: 'a',
        parentId: 'foreign-a',
        uploadKey: 'pending-a',
      })

    expect(absent).toThrow(FinalizeNotFoundError)
    expect(foreign).toThrow(FinalizeNotFoundError)
    expect(() => absent()).toThrow(/not found/i)
    expect(() => foreign()).toThrow(/not found/i)
  })

  it('happy path binds when actor owns parent and pending upload', () => {
    const store = seedStore()
    expect(
      finalizeUpload(store, {
        actor: 'actor-a',
        parentType: 'b',
        parentId: 'parent-b1',
        uploadKey: 'pending-a',
      }),
    ).toEqual({ ok: true })
  })
})
