import { MemoryRouter, Route, Routes } from 'react-router-dom'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { message } from 'antd'
import { beforeEach, describe, expect, it, vi } from 'vitest'

import { ResetPasswordPage } from './ResetPasswordPage'

const validateResetTokenMock = vi.fn()
const resetPasswordMock = vi.fn()

vi.mock('@/services/auth', () => ({
  validateResetToken: (token: string) => validateResetTokenMock(token),
  resetPassword: (payload: unknown) => resetPasswordMock(payload),
}))

function renderResetPasswordPage(initialEntry: string) {
  return render(
    <MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[initialEntry]}>
      <Routes>
        <Route path="/reset-password" element={<ResetPasswordPage />} />
      </Routes>
    </MemoryRouter>,
  )
}

describe('ResetPasswordPage', () => {
  beforeEach(() => {
    validateResetTokenMock.mockReset()
    resetPasswordMock.mockReset()

    validateResetTokenMock.mockResolvedValue({
      valid: true,
      email: 'user@example.com',
      expires_at: '2026-03-28T12:00:00Z',
    })
    resetPasswordMock.mockResolvedValue(undefined)

    vi.spyOn(message, 'success').mockImplementation(() => undefined as never)
    vi.spyOn(message, 'error').mockImplementation(() => undefined as never)
  })

  it('shows an invalid-link state when the reset token is missing', async () => {
    renderResetPasswordPage('/reset-password')

    expect(await screen.findByText('链接无效')).toBeInTheDocument()
    expect(validateResetTokenMock).not.toHaveBeenCalled()
    expect(screen.getByRole('button', { name: '重新申请' })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: '返回登录' })).toBeInTheDocument()
  })

  it('shows an invalid-link state when token validation fails', async () => {
    validateResetTokenMock.mockRejectedValueOnce(new Error('token invalid'))

    renderResetPasswordPage('/reset-password?token=expired-token')

    await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('expired-token'))

    expect(await screen.findByText('链接无效')).toBeInTheDocument()
    expect(screen.getByRole('button', { name: '重新申请' })).toBeInTheDocument()
  })

  it('renders the reset form after token validation succeeds', async () => {
    renderResetPasswordPage('/reset-password?token=token-123')

    await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('token-123'))

    expect(await screen.findByRole('heading', { name: '重置密码' })).toBeInTheDocument()
    expect(screen.getByPlaceholderText('新密码')).toBeInTheDocument()
    expect(screen.getByPlaceholderText('确认新密码')).toBeInTheDocument()
    expect(screen.getByRole('button', { name: '确认重置' })).toBeInTheDocument()
    expect(screen.getByText('user@example.com')).toBeInTheDocument()
  })

  it('submits the new password and shows the success state', async () => {
    const user = userEvent.setup()
    const { container } = renderResetPasswordPage('/reset-password?token=token-123')

    await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('token-123'))
    await waitFor(() => expect(container.querySelectorAll('input[type="password"]')).toHaveLength(2))

    const passwordInputs = Array.from(
      container.querySelectorAll('input[type="password"]'),
    ) as HTMLInputElement[]

    await user.type(passwordInputs[0], 'NewPass123!')
    await user.type(passwordInputs[1], 'NewPass123!')
    await user.click(screen.getByRole('button', { name: '确认重置' }))

    await waitFor(() =>
      expect(resetPasswordMock).toHaveBeenCalledWith({
        token: 'token-123',
        new_password: 'NewPass123!',
        confirm_password: 'NewPass123!',
      }),
    )

    expect(await screen.findByText('密码已重置')).toBeInTheDocument()
    expect(screen.getByRole('button', { name: '立即登录' })).toBeInTheDocument()
    expect(message.success).toHaveBeenCalledWith('密码重置成功')
  })

  it('surfaces backend failures when resetting the password', async () => {
    const user = userEvent.setup()
    const { container } = renderResetPasswordPage('/reset-password?token=token-123')
    resetPasswordMock.mockRejectedValueOnce(new Error('reset failed'))

    await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('token-123'))
    await waitFor(() => expect(container.querySelectorAll('input[type="password"]')).toHaveLength(2))

    const passwordInputs = Array.from(
      container.querySelectorAll('input[type="password"]'),
    ) as HTMLInputElement[]

    await user.type(passwordInputs[0], 'NewPass123!')
    await user.type(passwordInputs[1], 'NewPass123!')
    await user.click(screen.getByRole('button', { name: '确认重置' }))

    await waitFor(() => expect(message.error).toHaveBeenCalledWith('reset failed'))
  })
})
