/**
 * Auth token lifecycle regression — S1-005 / S1-006.
 */
import { describe, it, expect, vi } from 'vitest'
import type { TenantId, UserId } from '@zync/types'

describe('rotateRefreshToken (S1-005)', () => {
  it('allows only one rotation when two sequential calls use the same old hash', async () => {
    let revoked = false

    const tx = {
      update: vi.fn(() => ({
        set: vi.fn(() => ({
          where: vi.fn(() => ({
            returning: vi.fn(async () => (revoked ? [] : [{ id: 'rt-1' }])),
          })),
        })),
      })),
      insert: vi.fn(() => ({
        values: vi.fn(async () => undefined),
      })),
    }

    const db = {
      transaction: vi.fn(async (fn: (inner: typeof tx) => Promise<boolean>) => fn(tx)),
    }

    const { rotateRefreshToken } = await import('../../src/queries/auth-writes')

    const args = {
      oldTokenHash: 'old-hash',
      userId: '00000000-0000-4000-8000-000000000001' as UserId,
      tenantId: '00000000-0000-4000-8000-000000000002' as TenantId,
      newTokenHash: 'new-hash-1',
      expiresAt: new Date(Date.now() + 86_400_000),
    }

    const first = await rotateRefreshToken(db as never, args)
    expect(first).toBe(true)
    revoked = true

    const second = await rotateRefreshToken(db as never, {
      ...args,
      newTokenHash: 'new-hash-2',
    })
    expect(second).toBe(false)
  })
})

describe('consumeMagicLinkToken (S1-006)', () => {
  it('returns false on second sequential consume of the same token', async () => {
    let used = false

    const db = {
      update: vi.fn(() => ({
        set: vi.fn(() => ({
          where: vi.fn(() => ({
            returning: vi.fn(async () => (used ? [] : [{ id: 'ml-1' }])),
          })),
        })),
      })),
    }

    const { consumeMagicLinkToken } = await import('../../src/queries/magic-link-tokens')

    const first = await consumeMagicLinkToken(db as never, 'token-hash')
    expect(first).toBe(true)
    used = true

    const second = await consumeMagicLinkToken(db as never, 'token-hash')
    expect(second).toBe(false)
  })
})
