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

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

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

vi.mock('@/lib/product-access', () => ({
  productAccessFilter: vi.fn().mockReturnValue({}),
}))

import { prisma } from '@/lib/prisma'
import { authenticateApiRequest } from '@/lib/api-auth'
import { GET } from '@/app/api/products/[id]/sprint-membership-summary/route'

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

function makeRequest(url: string) {
  return new Request(url)
}

describe('GET /api/products/[id]/sprint-membership-summary', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockPrisma.product.findFirst.mockReset()
    mockPrisma.story.groupBy.mockReset()
    mockAuth.mockReset().mockResolvedValue({ userId: 'user-1' })
  })

  it('returns counts per PBI for happy path', async () => {
    mockPrisma.product.findFirst.mockResolvedValue({ id: 'p1' })
    mockPrisma.story.groupBy
      .mockResolvedValueOnce([
        { pbi_id: 'pbiA', _count: { _all: 5 } },
        { pbi_id: 'pbiB', _count: { _all: 3 } },
      ])
      .mockResolvedValueOnce([{ pbi_id: 'pbiA', _count: { _all: 2 } }])

    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?sprintId=sp-1&pbiIds=pbiA,pbiB',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })

    expect(res.status).toBe(200)
    const body = await res.json()
    expect(body).toEqual({
      pbiA: { total: 5, inSprint: 2 },
      pbiB: { total: 3, inSprint: 0 },
    })
  })

  it('rejects when pbiIds is missing', async () => {
    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?sprintId=sp-1',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })
    expect(res.status).toBe(400)
  })

  it('rejects when pbiIds is empty', async () => {
    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?sprintId=sp-1&pbiIds=',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })
    expect(res.status).toBe(400)
  })

  it('rejects when sprintId is missing', async () => {
    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?pbiIds=pbiA',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })
    expect(res.status).toBe(400)
  })

  it('returns 404 when product is not accessible', async () => {
    mockPrisma.product.findFirst.mockResolvedValue(null)
    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?sprintId=sp-1&pbiIds=pbiA',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })
    expect(res.status).toBe(404)
  })

  it('returns auth error when authenticate fails', async () => {
    mockAuth.mockResolvedValue({ error: 'Niet ingelogd', status: 401 })
    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?sprintId=sp-1&pbiIds=pbiA',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })
    expect(res.status).toBe(401)
  })

  it('returns zero counts for PBIs without stories', async () => {
    mockPrisma.product.findFirst.mockResolvedValue({ id: 'p1' })
    mockPrisma.story.groupBy
      .mockResolvedValueOnce([])
      .mockResolvedValueOnce([])

    const req = makeRequest(
      'http://localhost/api/products/p1/sprint-membership-summary?sprintId=sp-1&pbiIds=pbiA,pbiB',
    )
    const res = await GET(req, { params: Promise.resolve({ id: 'p1' }) })

    const body = await res.json()
    expect(body).toEqual({
      pbiA: { total: 0, inSprint: 0 },
      pbiB: { total: 0, inSprint: 0 },
    })
  })
})
