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

const { mockGroupBy, mockFindMany } = vi.hoisted(() => ({
  mockGroupBy: vi.fn(),
  mockFindMany: vi.fn(),
}))

vi.mock('@/lib/prisma', () => ({
  prisma: {
    claudeJob: {
      groupBy: mockGroupBy,
      findMany: mockFindMany,
    },
  },
}))

import { getVerifyResultStats } from '@/lib/insights/verify-stats'

const USER_ID = 'user-1'

const makeJob = (id: string, verifyResult: string, daysAgo: number) => {
  const finishedAt = new Date()
  finishedAt.setDate(finishedAt.getDate() - daysAgo)
  return {
    id,
    finished_at: finishedAt,
    task: { id: `task-${id}`, title: `Task ${id}` },
    product: { id: 'prod-1', name: 'Scrum4Me' },
    verify_result: verifyResult,
  }
}

beforeEach(() => {
  vi.clearAllMocks()
})

describe('getVerifyResultStats', () => {
  it('returns counts in ALIGNED→PARTIAL→EMPTY→DIVERGENT order', async () => {
    mockGroupBy.mockResolvedValue([
      { verify_result: 'DIVERGENT', _count: { _all: 2 } },
      { verify_result: 'ALIGNED', _count: { _all: 10 } },
      { verify_result: 'EMPTY', _count: { _all: 3 } },
      { verify_result: 'PARTIAL', _count: { _all: 1 } },
    ])
    mockFindMany.mockResolvedValue([])

    const stats = await getVerifyResultStats(USER_ID)

    expect(stats.counts.map(c => c.result)).toEqual([
      'ALIGNED', 'PARTIAL', 'EMPTY', 'DIVERGENT',
    ])
    expect(stats.counts.map(c => c.count)).toEqual([10, 1, 3, 2])
  })

  it('omits results with zero count from groupBy', async () => {
    mockGroupBy.mockResolvedValue([
      { verify_result: 'ALIGNED', _count: { _all: 5 } },
    ])
    mockFindMany.mockResolvedValue([])

    const stats = await getVerifyResultStats(USER_ID)

    expect(stats.counts).toHaveLength(1)
    expect(stats.counts[0]).toEqual({ result: 'ALIGNED', count: 5 })
  })

  it('maps topEmpty jobs correctly', async () => {
    mockGroupBy.mockResolvedValue([])
    const job = makeJob('j1', 'EMPTY', 2)
    // First findMany call → topEmpty, second → topDivergent
    mockFindMany
      .mockResolvedValueOnce([job])
      .mockResolvedValueOnce([])

    const stats = await getVerifyResultStats(USER_ID)

    expect(stats.topEmpty).toHaveLength(1)
    expect(stats.topEmpty[0]).toMatchObject({
      jobId: 'j1',
      taskId: 'task-j1',
      taskTitle: 'Task j1',
      productId: 'prod-1',
      productName: 'Scrum4Me',
    })
  })

  it('topDivergent is ordered most-recent first (from DB order)', async () => {
    mockGroupBy.mockResolvedValue([])
    const jobs = [
      makeJob('jOld', 'DIVERGENT', 10),
      makeJob('jNew', 'DIVERGENT', 1),
    ]
    mockFindMany
      .mockResolvedValueOnce([])       // topEmpty
      .mockResolvedValueOnce(jobs)     // topDivergent (already sorted by Prisma orderBy)

    const stats = await getVerifyResultStats(USER_ID)

    expect(stats.topDivergent.map(j => j.jobId)).toEqual(['jOld', 'jNew'])
  })

  it('returns empty stats when no jobs found', async () => {
    mockGroupBy.mockResolvedValue([])
    mockFindMany.mockResolvedValue([])

    const stats = await getVerifyResultStats(USER_ID)

    expect(stats.counts).toEqual([])
    expect(stats.topEmpty).toEqual([])
    expect(stats.topDivergent).toEqual([])
  })
})
