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

const { mockBoardPostExists } = vi.hoisted(() => ({
  mockBoardPostExists: vi.fn()
}))

vi.mock('../../../server/utils/auth.js', () => ({
  requireAuth: vi.fn()
}))

vi.mock('../../../server/utils/mongoose.js', () => ({
  connectDB: vi.fn()
}))

vi.mock('../../../server/models/boardPost.js', () => ({
  default: { exists: mockBoardPostExists }
}))

import { requireAuth } from '../../../server/utils/auth.js'
import handler from '../../../server/api/onboarding/status.get.js'
import { createMockEvent } from '../helpers/createMockEvent.js'

describe('GET /api/onboarding/status', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockBoardPostExists.mockResolvedValue(null)
  })

  // 1.1: Default state for new member — all false, completedAt null
  it('returns all goals false for a new member with no data', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: [],
      onboarding: {
        completedAt: null,
        eventPageVisited: false,
        boardPageVisited: false,
        wikiClicked: false,
      },
    })

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result).toEqual({
      goals: {
        hasProfileTags: false,
        hasVisitedEvent: false,
        hasEngagedBoard: false,
        hasClickedWiki: false,
      },
      skipped: {
        profileTags: false,
        visitEvent: false,
        board: false,
        wiki: false,
      },
      completedAt: null,
    })
  })

  // Skip flags surface from member.onboarding.skipped
  it('returns skipped map from member document', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: [],
      onboarding: {
        completedAt: null,
        eventPageVisited: false,
        boardPageVisited: false,
        wikiClicked: false,
        skipped: { profileTags: true, wiki: true },
      },
    })

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result.skipped).toEqual({
      profileTags: true,
      visitEvent: false,
      board: false,
      wiki: true,
    })
  })

  // 1.2: hasProfileTags true when craft tags present
  it('hasProfileTags is true when member has craft tags', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: ['game-design'],
      onboarding: {
        completedAt: null,
        eventPageVisited: false,
        boardPageVisited: false,
        wikiClicked: false,
      },
    })

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result.goals.hasProfileTags).toBe(true)
  })

  // 1.3: hasProfileTags false when no craft tags
  it('hasProfileTags is false when member has no craft tags', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: [],
      onboarding: {
        completedAt: null,
        eventPageVisited: false,
        boardPageVisited: false,
        wikiClicked: false,
      },
    })

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result.goals.hasProfileTags).toBe(false)
  })

  // 1.5: hasEngagedBoard true when visited AND has a BoardPost
  it('hasEngagedBoard is true when page visited and member has posted', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: [],
      onboarding: {
        completedAt: null,
        eventPageVisited: false,
        boardPageVisited: true,
        wikiClicked: false,
      },
    })
    mockBoardPostExists.mockResolvedValue({ _id: 'post-1' })

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result.goals.hasEngagedBoard).toBe(true)
    expect(mockBoardPostExists).toHaveBeenCalledWith({ author: 'member-1' })
  })

  // 1.6: hasEngagedBoard false when visited but no posts
  it('hasEngagedBoard is false when page visited but member has no posts', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: [],
      onboarding: {
        completedAt: null,
        eventPageVisited: false,
        boardPageVisited: true,
        wikiClicked: false,
      },
    })
    mockBoardPostExists.mockResolvedValue(null)

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result.goals.hasEngagedBoard).toBe(false)
  })

  // 1.9: Maps stored booleans directly
  it('maps stored onboarding booleans directly for visit and wiki goals', async () => {
    requireAuth.mockResolvedValue({
      _id: 'member-1',
      craftTags: [],
      onboarding: {
        completedAt: null,
        eventPageVisited: true,
        boardPageVisited: false,
        wikiClicked: true,
      },
    })

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })
    const result = await handler(event)

    expect(result.goals.hasVisitedEvent).toBe(true)
    expect(result.goals.hasEngagedBoard).toBe(false)
    expect(result.goals.hasClickedWiki).toBe(true)
  })

  // 1.11: Requires auth (401)
  it('returns 401 when not authenticated', async () => {
    requireAuth.mockRejectedValue(
      createError({ statusCode: 401, statusMessage: 'Authentication required' })
    )

    const event = createMockEvent({ method: 'GET', path: '/api/onboarding/status' })

    await expect(handler(event)).rejects.toMatchObject({ statusCode: 401 })
  })
})
