import { describe, expect, it } from 'vitest'
import type { Querier } from '@platform-modules/db'
import { MarketplaceMigrateError, pushSchema } from './migrate.js'
import type { MarketplaceSchema } from './schema.js'
import { freshDb, vendorCount } from './test-helpers.js'

describe('commerce-marketplace migrate', () => {
  it('pushSchema is idempotent (CREATE … IF NOT EXISTS) and creates a usable vendor table', async () => {
    // freshDb already runs pushSchema once against a real pglite DB
    const db = await freshDb()
    // a second push must not throw — IF NOT EXISTS guards the journal-free raw DDL
    await expect(pushSchema(db)).resolves.toBeUndefined()
    // the table exists and is queryable (proves the DDL applied, not just no-threw)
    expect(await vendorCount(db)).toBe(0)
  })

  it('wraps an underlying execute failure in MarketplaceMigrateError, carrying the root cause', async () => {
    const failing = {
      execute: async () => {
        throw new Error('boom: permission denied for schema public')
      },
    } as unknown as Querier<MarketplaceSchema>

    await expect(pushSchema(failing)).rejects.toMatchObject({
      name: 'MarketplaceMigrateError',
      code: 'MARKETPLACE_MIGRATE',
    })
    // the root cause must survive into detail (no ignored signals — operator diagnosability)
    await expect(pushSchema(failing)).rejects.toThrow(/boom: permission denied for schema public/)
  })

  it('non-Error throw values are stringified into detail', async () => {
    const failing = {
      execute: async () => {
        throw 'string failure' // eslint-disable-line no-throw-literal
      },
    } as unknown as Querier<MarketplaceSchema>

    await expect(pushSchema(failing)).rejects.toThrow(/string failure/)
  })

  it('MarketplaceMigrateError carries detail and a stable name/code', () => {
    const e = new MarketplaceMigrateError('something failed')
    expect(e).toBeInstanceOf(Error)
    expect(e.name).toBe('MarketplaceMigrateError')
    expect(e.code).toBe('MARKETPLACE_MIGRATE')
    expect(e.detail).toBe('something failed')
    expect(e.message).toContain('something failed')
  })
})
