import { fireEvent, screen, waitFor, within } from '@testing-library/react'
import { useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import { describe, expect, it, vi } from 'vitest'

import { useUnsavedChangesGuard } from '@/lib/useUnsavedChangesGuard'
import { renderWithProviders } from '@/test/render'

const GuardHarness = () => {
  const [dirty, setDirty] = useState (true)
  const location = useLocation ()
  const navigate = useNavigate ()
  const discard = vi.fn (() => setDirty (false))
  const { allowNextNavigation } = useUnsavedChangesGuard ({
    dirty,
    onDiscard: discard })

  return (
      <>
	<output aria-label="location">{location.pathname}{location.search}</output>
	<button type="button" onClick={() => navigate ('/next?tab=one')}>move</button>
	<button
	    type="button"
	    onClick={() => {
	      allowNextNavigation ()
	      navigate ('/allowed')
	    }}>
	  allowed move
	</button>
      </>)
}

describe ('useUnsavedChangesGuard', () => {
  it ('blocks route changes and resets a cancelled transition', async () => {
    renderWithProviders (<GuardHarness/>, { route: '/current' })

    fireEvent.click (screen.getByRole ('button', { name: 'move' }))

    expect (within (await screen.findByRole ('dialog')).getByText (
	'変更が破棄してページ移動しますか?')).toBeInTheDocument ()
    expect (screen.getByLabelText ('location')).toHaveTextContent ('/current')

    fireEvent.click (screen.getByRole ('button', { name: '取消' }))

    await waitFor (() => {
      expect (screen.queryByRole ('dialog')).not.toBeInTheDocument ()
    })
    expect (screen.getByLabelText ('location')).toHaveTextContent ('/current')
  })

  it ('proceeds with the blocked transition after discard is confirmed', async () => {
    renderWithProviders (<GuardHarness/>, { route: '/current' })

    fireEvent.click (screen.getByRole ('button', { name: 'move' }))
    fireEvent.click (await screen.findByRole ('button', {
      name: '変更を破棄して移動' }))

    await waitFor (() => {
      expect (screen.getByLabelText ('location')).toHaveTextContent ('/next?tab=one')
    })
  })

  it ('allows only the next navigation without leaving a bypass token', async () => {
    renderWithProviders (<GuardHarness/>, { route: '/current' })

    fireEvent.click (screen.getByRole ('button', { name: 'allowed move' }))
    await waitFor (() => {
      expect (screen.getByLabelText ('location')).toHaveTextContent ('/allowed')
    })

    fireEvent.click (screen.getByRole ('button', { name: 'move' }))

    expect (within (await screen.findByRole ('dialog')).getByText (
	'変更が破棄してページ移動しますか?')).toBeInTheDocument ()
    expect (screen.getByLabelText ('location')).toHaveTextContent ('/allowed')
  })
})
