import { fireEvent, screen, waitFor } from '@testing-library/react'
import { Route, Routes } from 'react-router-dom'
import { beforeEach, describe, expect, it, vi } from 'vitest'

import DeerjikistDetailPage from '@/pages/deerjikists/DeerjikistDetailPage'
import { buildTag } from '@/test/factories'
import { renderWithProviders } from '@/test/render'

const tagsApi = vi.hoisted (() => ({
  fetchDeerjikistsByTag: vi.fn (),
}))

const api = vi.hoisted (() => ({
  apiPut:     vi.fn (),
  isApiError: vi.fn (),
}))

const toastApi = vi.hoisted (() => ({
  toast: vi.fn (),
}))

vi.mock ('@/lib/tags', () => tagsApi)
vi.mock ('@/lib/api', () => api)
vi.mock ('@/components/ui/use-toast', () => toastApi)

const renderPage = () =>
  renderWithProviders (
      <Routes>
        <Route path="/tags/:id/deerjikists" element={<DeerjikistDetailPage/>}/>
      </Routes>,
      { route: '/tags/7/deerjikists' },
  )

describe ('DeerjikistDetailPage', () => {
  beforeEach (() => {
    vi.clearAllMocks ()
    api.isApiError.mockReturnValue (false)
  })

  it ('shows indexed validation errors returned for deerjikist rows', async () => {
    tagsApi.fetchDeerjikistsByTag.mockResolvedValueOnce ({
      tag:         buildTag ({ id: 7, name: 'deerjika', category: 'deerjikist' }),
      deerjikists: [{ platform: null, code: 'abc' }],
    })
    api.isApiError.mockReturnValue (true)
    api.apiPut.mockRejectedValueOnce ({
      response: {
        status: 422,
        data:   {
          type:        'validation_error',
          message:     '入力内容を確認してください．',
          errors:      { 'deerjikists.0.platform': ['プラットフォームを入力してください．'] },
          base_errors: [],
        },
      },
    })

    renderPage ()

    await screen.findByDisplayValue ('abc')
    fireEvent.submit (screen.getByRole ('button', { name: '更新' }).closest ('form')!)

    await waitFor (() => {
      expect (api.apiPut).toHaveBeenCalledWith (
          '/tags/7/deerjikists',
          [{ platform: null, code: 'abc' }],
      )
    })
    expect (await screen.findByText ('プラットフォームを入力してください．')).toBeInTheDocument ()
    expect (screen.getByRole ('combobox')).toHaveAttribute ('aria-invalid', 'true')
  })
})
