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

vi.mock('../api/client', () => ({
  default: {
    post: vi.fn(),
    get: vi.fn(),
    interceptors: {
      request: { use: vi.fn() },
      response: { use: vi.fn() },
    },
  },
}))

import api from '../api/client'

const mockNavigate = vi.fn()
vi.mock('react-router-dom', async (importOriginal) => {
  const actual = await importOriginal()
  return {
    ...actual,
    useNavigate: () => mockNavigate,
  }
})

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

  const renderPage = (search = '') =>
    render(
      <MemoryRouter initialEntries={[`/reset-password${search}`]}>
        <Routes>
          <Route path="/reset-password" element={<ResetPassword />} />
        </Routes>
      </MemoryRouter>
    )

  it('renders form', () => {
    renderPage('?token=abc')
    // Use getAllByText since "Новый пароль" appears as h1 and label
    expect(screen.getAllByText('Новый пароль').length).toBeGreaterThan(0)
    expect(screen.getByPlaceholderText('Минимум 8 символов')).toBeInTheDocument()
    expect(screen.getByText('Сохранить пароль')).toBeInTheDocument()
  })

  it('shows error when no token on submit', async () => {
    renderPage()
    fireEvent.change(screen.getByPlaceholderText('Минимум 8 символов'), {
      target: { value: 'newpassword123' },
    })
    fireEvent.click(screen.getByText('Сохранить пароль'))

    await waitFor(() => {
      expect(screen.getByText('Токен не найден')).toBeInTheDocument()
    })
  })

  it('shows success state on successful reset', async () => {
    api.post.mockResolvedValueOnce({})
    renderPage('?token=valid-token')

    fireEvent.change(screen.getByPlaceholderText('Минимум 8 символов'), {
      target: { value: 'newpassword123' },
    })
    fireEvent.click(screen.getByText('Сохранить пароль'))

    await waitFor(() => {
      expect(screen.getByText('Пароль изменён! 🎉')).toBeInTheDocument()
    }, { timeout: 3000 })
  })

  it('shows error on failure', async () => {
    api.post.mockRejectedValueOnce({ response: { data: { error: 'Token invalid' } } })
    renderPage('?token=bad-token')

    fireEvent.change(screen.getByPlaceholderText('Минимум 8 символов'), {
      target: { value: 'newpassword123' },
    })
    fireEvent.click(screen.getByText('Сохранить пароль'))

    await waitFor(() => {
      expect(screen.getByText('Token invalid')).toBeInTheDocument()
    }, { timeout: 3000 })
  })

  it('toggles password visibility', () => {
    renderPage('?token=abc')
    const passwordInput = screen.getByPlaceholderText('Минимум 8 символов')
    expect(passwordInput.type).toBe('password')

    const toggleBtn = passwordInput.parentElement.querySelector('button[type="button"]')
    fireEvent.click(toggleBtn)
    expect(passwordInput.type).toBe('text')
  })

  it('calls correct API endpoint', async () => {
    api.post.mockResolvedValueOnce({})
    renderPage('?token=mytoken')

    fireEvent.change(screen.getByPlaceholderText('Минимум 8 символов'), {
      target: { value: 'mynewpassword' },
    })
    fireEvent.click(screen.getByText('Сохранить пароль'))

    await waitFor(() => {
      expect(api.post).toHaveBeenCalledWith('/auth/reset-password', {
        token: 'mytoken',
        new_password: 'mynewpassword',
      })
    }, { timeout: 3000 })
  })
})
