import { describe, it, expect, vi, beforeEach } from 'vitest'

vi.mock('../../../server/models/member.js', () => {
  const mockSave = vi.fn().mockResolvedValue(undefined)
  function MockMember(data) {
    Object.assign(this, data)
    this._id = 'new-member-123'
    this.status = data.status || 'pending_payment'
    this.save = mockSave
  }
  MockMember.findOne = vi.fn()
  MockMember.findByIdAndUpdate = vi.fn()
  MockMember._mockSave = mockSave
  return { default: MockMember }
})
vi.mock('../../../server/utils/mongoose.js', () => ({ connectDB: vi.fn() }))
vi.mock('../../../server/utils/validateBody.js', () => ({ validateBody: vi.fn() }))
vi.mock('../../../server/utils/schemas.js', () => ({ memberCreateSchema: {} }))
vi.mock('../../../server/utils/slack.ts', () => ({
  getSlackService: vi.fn().mockReturnValue(null)
}))
vi.mock('../../../server/utils/resend.js', () => ({
  sendWelcomeEmail: vi.fn().mockResolvedValue(undefined)
}))

import Member from '../../../server/models/member.js'
import { validateBody } from '../../../server/utils/validateBody.js'
import { sendWelcomeEmail } from '../../../server/utils/resend.js'
import createHandler from '../../../server/api/members/create.post.js'
import { createMockEvent } from '../helpers/createMockEvent.js'

describe('members/create.post handler', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    Member.findOne.mockResolvedValue(null)
    Member._mockSave.mockResolvedValue(undefined)
    validateBody.mockResolvedValue({
      email: 'new@example.com',
      name: 'New Member',
      circle: 'community',
      contributionTier: '0'
    })
  })

  it('validates request body via memberCreateSchema', async () => {
    const event = createMockEvent({ method: 'POST', path: '/api/members/create' })

    await createHandler(event)

    expect(validateBody).toHaveBeenCalledOnce()
    expect(validateBody).toHaveBeenCalledWith(event, expect.any(Object))
  })

  it('rejects duplicate email with 409', async () => {
    Member.findOne.mockResolvedValue({ _id: 'existing-123', email: 'new@example.com' })

    const event = createMockEvent({ method: 'POST', path: '/api/members/create' })

    await expect(createHandler(event)).rejects.toMatchObject({
      statusCode: 409,
      statusMessage: 'A member with this email already exists'
    })
  })

  it('does not expose helcimCustomerId or role in response', async () => {
    validateBody.mockResolvedValue({
      email: 'new@example.com',
      name: 'New Member',
      circle: 'community',
      contributionTier: '0',
      helcimCustomerId: 'cust-999',
      role: 'admin'
    })

    const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
    const result = await createHandler(event)

    expect(result.member).not.toHaveProperty('helcimCustomerId')
    expect(result.member).not.toHaveProperty('role')
    expect(result.success).toBe(true)
    expect(result.member).toEqual({
      id: 'new-member-123',
      email: 'new@example.com',
      name: 'New Member',
      circle: 'community',
      contributionTier: '0',
      status: 'pending_payment'
    })
  })

  it('succeeds when Slack service is unavailable', async () => {
    const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
    const result = await createHandler(event)

    expect(result.success).toBe(true)
    expect(result.member.email).toBe('new@example.com')
  })

  it('succeeds when welcome email fails', async () => {
    sendWelcomeEmail.mockRejectedValue(new Error('email service down'))

    const event = createMockEvent({ method: 'POST', path: '/api/members/create' })
    const result = await createHandler(event)

    expect(result.success).toBe(true)
    expect(result.member.email).toBe('new@example.com')
    expect(sendWelcomeEmail).toHaveBeenCalledOnce()
  })
})
