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

vi.mock('@/lib/prisma', () => ({
  prisma: {
    sprint: {
      findFirst: vi.fn(),
    },
    story: {
      findFirst: vi.fn(),
    },
  },
}))

vi.mock('@/lib/api-auth', () => ({
  authenticateApiRequest: vi.fn(),
}))

import { prisma } from '@/lib/prisma'
import { authenticateApiRequest } from '@/lib/api-auth'
import { GET as getNextStory } from '@/app/api/products/[id]/next-story/route'

const mockPrisma = prisma as unknown as {
  sprint: { findFirst: ReturnType<typeof vi.fn> }
  story: { findFirst: ReturnType<typeof vi.fn> }
}
const mockAuth = authenticateApiRequest as ReturnType<typeof vi.fn>

const SPRINT = { id: 'sprint-1', product_id: 'prod-1', status: 'OPEN' }
const STORY = {
  id: 'story-1',
  title: 'Account aanmaken',
  description: 'Als bezoeker wil ik een account aanmaken.',
  acceptance_criteria: '- Gebruikersnaam verplicht',
  tasks: [
    { id: 'task-1', title: 'Formulier bouwen', description: null, priority: 1, sort_order: 1, status: 'TO_DO' },
    { id: 'task-2', title: 'Validatie toevoegen', description: null, priority: 2, sort_order: 2, status: 'TO_DO' },
  ],
}

function makeRequest(productId = 'prod-1'): [Request, { params: Promise<{ id: string }> }] {
  return [
    new Request(`http://localhost/api/products/${productId}/next-story`, {
      method: 'GET',
      headers: { Authorization: 'Bearer test-token' },
    }),
    { params: Promise.resolve({ id: productId }) },
  ]
}

describe('GET /api/products/:id/next-story', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockAuth.mockResolvedValue({ userId: 'user-1', isDemo: false })
  })

  // TC-NS-04
  it('returns 404 when product has no active sprint', async () => {
    mockPrisma.sprint.findFirst.mockResolvedValue(null)

    const res = await getNextStory(...makeRequest())
    const data = await res.json()

    expect(res.status).toBe(404)
    expect(data.error).toBeTruthy()
  })

  // TC-NS-05
  it('returns 404 when active sprint has no IN_SPRINT stories', async () => {
    mockPrisma.sprint.findFirst.mockResolvedValue(SPRINT)
    mockPrisma.story.findFirst.mockResolvedValue(null)

    const res = await getNextStory(...makeRequest())
    const data = await res.json()

    expect(res.status).toBe(404)
    expect(data.error).toBeTruthy()
  })

  // TC-NS-06
  it('returns the highest-priority story with its tasks', async () => {
    mockPrisma.sprint.findFirst.mockResolvedValue(SPRINT)
    mockPrisma.story.findFirst.mockResolvedValue(STORY)

    const res = await getNextStory(...makeRequest())
    const data = await res.json()

    expect(res.status).toBe(200)
    expect(data).toMatchObject({
      id: 'story-1',
      title: 'Account aanmaken',
      description: 'Als bezoeker wil ik een account aanmaken.',
      acceptance_criteria: '- Gebruikersnaam verplicht',
    })
    expect(data.tasks).toHaveLength(2)
    expect(data.tasks[0]).toMatchObject({ id: 'task-1', status: 'todo' })
  })

  it('queries story ordered by sort_order only', async () => {
    mockPrisma.sprint.findFirst.mockResolvedValue(SPRINT)
    mockPrisma.story.findFirst.mockResolvedValue(STORY)

    await getNextStory(...makeRequest())

    expect(mockPrisma.story.findFirst).toHaveBeenCalledWith(
      expect.objectContaining({
        orderBy: [{ sort_order: 'asc' }],
      })
    )
  })
})
