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

import SettingPage from '@/pages/users/SettingPage'
import { buildUser } from '@/test/factories'
import { renderWithProviders } from '@/test/render'

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

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

vi.mock ('@/lib/api', () => api)
vi.mock ('@/components/ui/use-toast', () => toastApi)
vi.mock ('@/components/users/UserCodeDialogue', () => ({
  default: () => null,
}))
vi.mock ('@/components/users/InheritDialogue', () => ({
  default: () => null,
}))

describe ('SettingPage', () => {
  it ('shows loading when user is absent', () => {
    renderWithProviders (<SettingPage user={null} setUser={vi.fn ()}/>)

    expect (screen.getByText ('Loading...')).toBeInTheDocument ()
  })

  it ('updates the current user name', async () => {
    const user = buildUser ({ id: 11, name: 'old' })
    const setUser = vi.fn ()
    api.apiPut.mockResolvedValueOnce ({ ...user, name: 'new' })

    renderWithProviders (<SettingPage user={user} setUser={setUser}/>)

    fireEvent.change (screen.getByRole ('textbox'), { target: { value: 'new' } })
    fireEvent.click (screen.getByRole ('button', { name: '更新' }))

    await waitFor (() => {
      expect (api.apiPut).toHaveBeenCalledWith (
          '/users/11',
          expect.any (FormData),
          { headers: { 'Content-Type': 'multipart/form-data' } },
      )
    })
    const formData = api.apiPut.mock.calls[0]?.[1] as FormData
    expect (formData.get ('name')).toBe ('new')
    expect (setUser).toHaveBeenCalled ()
    expect (toastApi.toast).toHaveBeenCalledWith ({ title: '設定を更新しました．' })
  })
})
