import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import { MemoryRouter, Route, Routes } from 'react-router-dom'
import { HelmetProvider } from 'react-helmet-async'

import { VerifyEmailPage } from '../VerifyEmailPage'
import { authApi } from '@/api/auth'
import { useAuthStore } from '@/store/authStore'
import type { User } from '@/types'

vi.mock('@/api/auth', () => ({
  authApi: {
    verifyEmail: vi.fn(),
    sendVerificationEmail: vi.fn(),
    me: vi.fn(),
  },
}))

vi.mock('@/lib/toast', () => ({
  toast: {
    success: vi.fn(),
    error: vi.fn(),
  },
}))

function makeUser(overrides: Partial<User> = {}): User {
  return {
    id: 'user-1',
    email: 'test@example.com',
    name: 'Test User',
    role: 'engineer',
    is_super_admin: false,
    is_active: true,
    must_change_password: false,
    account_id: 'acct-1',
    account_role: 'engineer',
    team_id: null,
    created_at: '2026-05-01T00:00:00Z',
    last_login: null,
    phone: null,
    job_title: null,
    timezone: 'UTC',
    avatar_url: null,
    email_verified_at: null,
    ...overrides,
  }
}

function renderPage(initialPath: string) {
  return render(
    <HelmetProvider>
      <MemoryRouter initialEntries={[initialPath]}>
        <Routes>
          <Route path="/verify-email" element={<VerifyEmailPage />} />
          <Route path="/home" element={<div>dashboard</div>} />
        </Routes>
      </MemoryRouter>
    </HelmetProvider>,
  )
}

describe('VerifyEmailPage', () => {
  beforeEach(() => {
    vi.useFakeTimers({ shouldAdvanceTime: true })
    useAuthStore.setState({
      user: null,
      token: null,
      isAuthenticated: false,
    })
    vi.mocked(authApi.me).mockResolvedValue(
      makeUser({ email_verified_at: '2026-05-06T00:00:00Z' }),
    )
  })

  afterEach(() => {
    vi.useRealTimers()
    vi.clearAllMocks()
  })

  it('shows success and redirects on valid token', async () => {
    useAuthStore.setState({ user: makeUser() })
    // Override fetchUser to avoid hitting axios/XHR in jsdom — the page calls
    // it after a successful verify to refresh `email_verified_at`.
    useAuthStore.setState({ fetchUser: vi.fn().mockResolvedValue(undefined) })
    vi.mocked(authApi.verifyEmail).mockResolvedValue(undefined)

    renderPage('/verify-email?token=valid-token')

    await waitFor(() => {
      expect(authApi.verifyEmail).toHaveBeenCalledWith('valid-token')
    })

    await waitFor(() => {
      expect(screen.getByText(/Email verified/i)).toBeInTheDocument()
    })

    // Advance past the redirect delay.
    vi.advanceTimersByTime(2000)

    await waitFor(() => {
      expect(screen.getByText('dashboard')).toBeInTheDocument()
    })
  })

  it('shows already-verified state when user is already verified', async () => {
    useAuthStore.setState({
      user: makeUser({ email_verified_at: '2026-05-05T00:00:00Z' }),
    })

    renderPage('/verify-email?token=any-token')

    await waitFor(() => {
      expect(
        screen.getByText(/already verified/i),
      ).toBeInTheDocument()
    })

    // The verify endpoint must NOT have been called when the user is already
    // verified — that would burn a perfectly good token for no reason.
    expect(authApi.verifyEmail).not.toHaveBeenCalled()
  })

  it('only calls verifyEmail once even if the effect re-runs (strict-mode guard)', async () => {
    useAuthStore.setState({ user: makeUser() })
    useAuthStore.setState({ fetchUser: vi.fn().mockResolvedValue(undefined) })
    vi.mocked(authApi.verifyEmail).mockResolvedValue(undefined)

    const { rerender } = render(
      <HelmetProvider>
        <MemoryRouter initialEntries={['/verify-email?token=valid-token']}>
          <Routes>
            <Route path="/verify-email" element={<VerifyEmailPage />} />
            <Route path="/home" element={<div>dashboard</div>} />
          </Routes>
        </MemoryRouter>
      </HelmetProvider>,
    )

    // Force a re-render to simulate React 19 strict-mode double-invoke.
    rerender(
      <HelmetProvider>
        <MemoryRouter initialEntries={['/verify-email?token=valid-token']}>
          <Routes>
            <Route path="/verify-email" element={<VerifyEmailPage />} />
            <Route path="/home" element={<div>dashboard</div>} />
          </Routes>
        </MemoryRouter>
      </HelmetProvider>,
    )

    await waitFor(() => {
      expect(authApi.verifyEmail).toHaveBeenCalled()
    })

    expect(authApi.verifyEmail).toHaveBeenCalledTimes(1)
  })

  it('shows an error state with a resend CTA on invalid token', async () => {
    useAuthStore.setState({ user: makeUser() })
    vi.mocked(authApi.verifyEmail).mockRejectedValue(
      Object.assign(new Error('boom'), {
        response: { data: { detail: 'Token expired' } },
      }),
    )

    renderPage('/verify-email?token=stale-token')

    await waitFor(() => {
      expect(screen.getByText(/Verification failed/i)).toBeInTheDocument()
    })
    expect(screen.getByText(/Token expired/i)).toBeInTheDocument()
    expect(screen.getByTestId('resend-button')).toBeInTheDocument()
  })
})
