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

const { mockGetSession, mockFindFirstJob, mockFindManyPrice } = vi.hoisted(() => ({
  mockGetSession: vi.fn(),
  mockFindFirstJob: vi.fn(),
  mockFindManyPrice: vi.fn(),
}))

vi.mock('@/lib/auth', () => ({ getSession: mockGetSession }))
vi.mock('@/lib/prisma', () => ({
  prisma: {
    claudeJob: { findFirst: mockFindFirstJob },
    modelPrice: { findMany: mockFindManyPrice },
  },
}))

import { GET } from '@/app/api/jobs/[id]/route'

function makeParams(id = 'job-1'): { params: Promise<{ id: string }> } {
  return { params: Promise.resolve({ id }) }
}

function makeRequest(id = 'job-1'): Request {
  return new Request(`http://localhost/api/jobs/${id}`)
}

const RAW_JOB = {
  id: 'job-1',
  kind: 'TASK_IMPLEMENTATION' as const,
  status: 'DONE' as const,
  model_id: 'claude-sonnet-4-6',
  input_tokens: 100,
  output_tokens: 50,
  cache_read_tokens: 0,
  cache_write_tokens: 0,
  branch: 'feat/test',
  pr_url: null,
  error: null,
  summary: 'Done',
  verify_result: 'ALIGNED' as const,
  started_at: new Date('2026-01-01T10:00:00Z'),
  finished_at: new Date('2026-01-01T10:05:00Z'),
  created_at: new Date('2026-01-01T09:59:00Z'),
  sprint_run_id: null,
  task: {
    code: 'T-42',
    title: 'Some task',
    description: null,
    implementation_plan: 'Do the thing',
    story: { code: 'S-10', pbi: { code: 'PBI-5' } },
  },
  idea: null,
  product: { name: 'Scrum4Me', code: 'SCR' },
  sprint_run: null,
}

describe('GET /api/jobs/:id', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockGetSession.mockResolvedValue({ userId: 'user-1' })
    mockFindFirstJob.mockResolvedValue(RAW_JOB)
    mockFindManyPrice.mockResolvedValue([])
  })

  it('returns 401 when not logged in', async () => {
    mockGetSession.mockResolvedValue({ userId: undefined })
    const res = await GET(makeRequest() as never, makeParams())
    expect(res.status).toBe(401)
    const body = await res.json()
    expect(body.error).toBeTruthy()
  })

  it('returns 404 when job not found', async () => {
    mockFindFirstJob.mockResolvedValue(null)
    const res = await GET(makeRequest() as never, makeParams())
    expect(res.status).toBe(404)
    const body = await res.json()
    expect(body.error).toBeTruthy()
  })

  it('queries with user_id filter to prevent cross-user access', async () => {
    await GET(makeRequest() as never, makeParams())
    expect(mockFindFirstJob).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { id: 'job-1', user_id: 'user-1' },
      })
    )
  })

  it('returns 200 with mapped job shape including breadcrumb codes', async () => {
    const res = await GET(makeRequest() as never, makeParams())
    expect(res.status).toBe(200)
    const body = await res.json()
    expect(body).toMatchObject({
      id: 'job-1',
      kind: 'TASK_IMPLEMENTATION',
      status: 'DONE',
      taskCode: 'T-42',
      taskTitle: 'Some task',
      productCode: 'SCR',
      storyCode: 'S-10',
      pbiCode: 'PBI-5',
      branch: 'feat/test',
    })
  })
})
