import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import useDocumentTitle from '@/hooks/use-document-title'
import { changePasswordWithToken } from '@/service/common'
import { useVerifyForgotPasswordToken } from '@/service/use-common'
import ChangePasswordForm from './ChangePasswordForm'

const mockReplace = vi.fn()
vi.mock('@/next/navigation', () => ({
  useSearchParams: () => new URLSearchParams('token=url-token-t1'),
  useRouter: () => ({ replace: mockReplace }),
}))

vi.mock('@/service/use-common', () => ({
  useVerifyForgotPasswordToken: vi.fn(),
}))

vi.mock('@/service/common', () => ({
  changePasswordWithToken: vi.fn(),
}))

vi.mock('@/hooks/use-document-title', () => ({
  __esModule: true,
  default: vi.fn(),
}))

vi.mock('@/utils/var', () => ({ basePath: '' }))

type UseVerifyResult = ReturnType<typeof useVerifyForgotPasswordToken>
const mockUseVerify = vi.mocked(useVerifyForgotPasswordToken)
const mockChangePassword = vi.mocked(changePasswordWithToken)
const mockUseDocumentTitle = vi.mocked(useDocumentTitle)

const VALID_PASSWORD = 'ValidPass123!'

describe('ChangePasswordForm', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('uses the loading title while the token is being verified', () => {
    mockUseVerify.mockReturnValue({
      data: undefined,
      refetch: vi.fn(),
    } as unknown as UseVerifyResult)

    render(<ChangePasswordForm />)

    expect(mockUseDocumentTitle).toHaveBeenLastCalledWith('common.loading')
  })

  describe('when token is valid', () => {
    const T2 = 'verified-token-t2'

    beforeEach(() => {
      mockUseVerify.mockReturnValue({
        data: { result: 'success', is_valid: true, email: 'user@example.com', token: T2 },
        refetch: vi.fn(),
      } as unknown as UseVerifyResult)
    })

    it('renders the password form', () => {
      render(<ChangePasswordForm />)
      expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('login.changePassword')
      expect(mockUseDocumentTitle).toHaveBeenLastCalledWith('login.changePassword')
    })

    it('submits with T2 (from validity response), NOT T1 (from URL)', async () => {
      mockChangePassword.mockResolvedValue({ result: 'success' })

      render(<ChangePasswordForm />)

      const inputs = Array.from(
        document.querySelectorAll<HTMLInputElement>('input[type="password"]'),
      ) as [HTMLInputElement, HTMLInputElement]
      fireEvent.change(inputs[0], { target: { value: VALID_PASSWORD } })
      fireEvent.change(inputs[1], { target: { value: VALID_PASSWORD } })

      fireEvent.click(screen.getByRole('button', { name: /common\.operation\.reset/ }))

      await waitFor(() => {
        expect(mockChangePassword).toHaveBeenCalledWith({
          url: '/forgot-password/resets',
          body: {
            token: T2,
            new_password: VALID_PASSWORD,
            password_confirm: VALID_PASSWORD,
          },
        })
      })
    })

    it('uses the success title after the password is changed', async () => {
      mockChangePassword.mockResolvedValue({ result: 'success' })

      render(<ChangePasswordForm />)

      const inputs = Array.from(
        document.querySelectorAll<HTMLInputElement>('input[type="password"]'),
      ) as [HTMLInputElement, HTMLInputElement]
      fireEvent.change(inputs[0], { target: { value: VALID_PASSWORD } })
      fireEvent.change(inputs[1], { target: { value: VALID_PASSWORD } })
      fireEvent.click(screen.getByRole('button', { name: /common\.operation\.reset/ }))

      expect(
        await screen.findByRole('heading', { level: 1, name: 'login.passwordChangedTip' }),
      ).toBeInTheDocument()
      expect(mockUseDocumentTitle).toHaveBeenLastCalledWith('login.passwordChangedTip')
    })
  })

  describe('when token is invalid', () => {
    beforeEach(() => {
      mockUseVerify.mockReturnValue({
        data: { result: 'success', is_valid: false, email: '', token: '' },
        refetch: vi.fn(),
      } as unknown as UseVerifyResult)
    })

    it('shows invalid token state and no form', () => {
      render(<ChangePasswordForm />)
      expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('login.invalid')
      expect(mockUseDocumentTitle).toHaveBeenLastCalledWith('login.invalid')
      expect(
        screen.queryByRole('button', { name: /common\.operation\.reset/ }),
      ).not.toBeInTheDocument()
    })
  })
})
