import { describe, it, expect } from 'vitest'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'

const eventsDir = resolve(import.meta.dirname, '../../../server/api/events/[id]')

describe('register.post.js', () => {
  const source = readFileSync(resolve(eventsDir, 'register.post.js'), 'utf-8')

  it('uses validateBody for input validation', () => {
    expect(source).toContain('validateBody(event')
  })

  it('checks for duplicate registration with case-insensitive email', () => {
    expect(source).toContain('email.toLowerCase()')
  })

  it('uses validateTicketPurchase for gating (covers membersOnly, deadline, sold-out, etc.)', () => {
    expect(source).toContain('validateTicketPurchase(')
  })

  it('enforces series-pass gate via checkUserSeriesPass', () => {
    expect(source).toContain('checkUserSeriesPass(')
    expect(source).toContain('requiresSeriesTicket')
    expect(source).toContain('seriesTicketReference')
  })

  it('does not let email failure block registration', () => {
    // The await call (not the import) must be wrapped in try/catch
    const emailCallIndex = source.indexOf('await sendEventRegistrationEmail')
    expect(emailCallIndex).toBeGreaterThan(-1)

    // A try block immediately precedes the email call
    const precedingSource = source.slice(0, emailCallIndex)
    const lastTryIndex = precedingSource.lastIndexOf('try')
    expect(lastTryIndex).toBeGreaterThan(-1)

    // The catch after the email call should log but not re-throw
    const afterEmail = source.slice(emailCallIndex)
    const catchBlock = afterEmail.match(/catch\s*\(\w+\)\s*\{[^}]*\}/s)
    expect(catchBlock).not.toBeNull()
    expect(catchBlock[0]).toContain('console.error')
  })
})

describe('cancel-registration.post.js', () => {
  const source = readFileSync(resolve(eventsDir, 'cancel-registration.post.js'), 'utf-8')

  it('uses validateBody for input validation', () => {
    expect(source).toContain('validateBody(event')
  })

  it('finds registration by email', () => {
    expect(source).toContain('email.toLowerCase()')
  })

  it('notifies waitlist after cancellation', () => {
    expect(source).toContain('waitlist')
    expect(source).toContain('sendWaitlistNotificationEmail')
  })

  it('does not require auth', () => {
    expect(source).not.toContain('requireAuth')
  })
})

describe('tickets/purchase.post.js', () => {
  const source = readFileSync(resolve(eventsDir, 'tickets/purchase.post.js'), 'utf-8')

  it('uses validateBody for input validation', () => {
    expect(source).toContain('validateBody(event, ticketPurchaseSchema)')
  })

  it('upserts a guest Member when consent given and no existing Member', () => {
    expect(source).toContain('body.createAccount')
    expect(source).toContain('findOneAndUpdate')
    expect(source).toContain('$setOnInsert')
    expect(source).toContain('status: "guest"')
    expect(source).toContain('upsert: true')
  })

  it('treats inactive Members (guest, suspended, cancelled) as non-members for pricing and validation', () => {
    // Only members with access (active or pending_payment) get member pricing.
    // hasMemberAccess is the shared gate in server/utils/tickets.js.
    expect(source).toContain('hasMemberAccess(member)')
  })

  it('sets an auth cookie for new guests and returning guests', () => {
    expect(source).toContain('setAuthCookie(event, member)')
    expect(source).toContain('accountCreated || member.status === "guest"')
  })

  it('does not auto-login existing non-guest members (hijack prevention)', () => {
    // Requires sign-in flag for existing real members — plan §2
    expect(source).toContain('requiresSignIn = true')
  })

  it('passes requiresSignIn to confirmation email', () => {
    expect(source).toContain('sendEventRegistrationEmail(registration, eventData, { requiresSignIn })')
  })

  it('includes accountCreated and signedIn in response', () => {
    expect(source).toContain('accountCreated,')
    expect(source).toContain('signedIn,')
  })

  it('does not block registration when email fails', () => {
    const emailCallIndex = source.indexOf('await sendEventRegistrationEmail')
    expect(emailCallIndex).toBeGreaterThan(-1)
    const afterEmail = source.slice(emailCallIndex)
    const catchBlock = afterEmail.match(/catch\s*\(\w+\)\s*\{[^}]*\}/s)
    expect(catchBlock).not.toBeNull()
    expect(catchBlock[0]).toContain('console.error')
  })
})
