import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { http } from 'msw'
import { server } from '../../../../tests/msw/server'
import { jsonResponse, errorResponse } from '../../../../tests/msw/helpers'
import { renderWithProviders, screen, waitFor, userEvent } from '../../../../tests/helpers/render'
import { seedBearer, clearBearer } from '../../../../tests/helpers/auth'
import { AdminPage } from '..'

// v2 admin — AI Recognition Engine panel. Covers GET → render telemetry,
// edit value via stepper / input, APPLY → PATCH, RESET → discards draft,
// PATCH 500 → inline error.
//
// Both AI and GPS panels render APPLY buttons; AI is the first one in DOM
// order. We pick [0] from getAllByRole rather than coupling to internal markup.

function aiApplyButton(): HTMLElement {
  return screen.getAllByRole('button', { name: /apply/i })[0]
}
function aiResetButton(): HTMLElement {
  return screen.getByRole('button', { name: /reset/i })
}

beforeEach(() => {
  seedBearer()
})
afterEach(() => {
  clearBearer()
})

describe('AdminPage — AI Recognition Engine', () => {
  it('renders initial settings + telemetry from GET /api/admin/ai-settings', async () => {
    renderWithProviders(<AdminPage />)
    expect(await screen.findByText('YOLOV8-X · CKPT-241')).toBeInTheDocument()
    expect(screen.getByDisplayValue('4')).toBeInTheDocument()
    expect(screen.getByDisplayValue('25')).toBeInTheDocument()
  })

  it('APPLY sends PATCH with edited settings and reflects telemetry refresh', async () => {
    const calls: { body: unknown }[] = []
    server.use(
      http.patch('/api/admin/ai-settings', async ({ request }) => {
        const body = await request.json()
        calls.push({ body })
        return jsonResponse({
          settings: { framesToRecognize: 8, minSecondsBetween: 2, minConfidence: 25 },
          telemetry: {
            model: 'YOLOV8-X', checkpoint: 'CKPT-242',
            lastRunAt: '2026-05-18T12:00:00Z', frames: 99, avgConfidence: 80,
          },
        })
      }),
    )
    renderWithProviders(<AdminPage />)
    await screen.findByText('YOLOV8-X · CKPT-241')

    const framesInput = screen.getByDisplayValue('4') as HTMLInputElement
    await userEvent.clear(framesInput)
    await userEvent.type(framesInput, '8')

    await userEvent.click(aiApplyButton())

    await waitFor(() => expect(calls.length).toBe(1))
    expect((calls[0].body as { framesToRecognize: number }).framesToRecognize).toBe(8)
    expect(await screen.findByText(/CKPT-242/)).toBeInTheDocument()
  })

  it('RESET reverts draft to the last persisted value (no PATCH)', async () => {
    const patchCalls: unknown[] = []
    server.use(
      http.patch('/api/admin/ai-settings', () => {
        patchCalls.push({})
        return jsonResponse({})
      }),
    )
    renderWithProviders(<AdminPage />)
    await screen.findByText('YOLOV8-X · CKPT-241')

    const framesInput = screen.getByDisplayValue('4') as HTMLInputElement
    await userEvent.clear(framesInput)
    await userEvent.type(framesInput, '9')
    expect(screen.getByDisplayValue('9')).toBeInTheDocument()

    await userEvent.click(aiResetButton())

    expect(screen.getByDisplayValue('4')).toBeInTheDocument()
    expect(patchCalls.length).toBe(0)
  })

  it('PATCH 500 surfaces an inline error', async () => {
    server.use(
      http.patch('/api/admin/ai-settings', () => errorResponse(500, 'boom')),
    )
    renderWithProviders(<AdminPage />)
    await screen.findByText('YOLOV8-X · CKPT-241')

    await userEvent.click(aiApplyButton())

    const alert = await screen.findByRole('alert')
    expect(alert.textContent ?? '').toMatch(/failed to save ai/i)
  })
})
