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

import { OAuthCallbackPage } from '../OAuthCallbackPage'
import { authApi } from '@/api/auth'

vi.mock('@/api/auth', () => ({
  authApi: {
    googleCallback: vi.fn(),
    microsoftCallback: vi.fn(),
  },
}))

vi.mock('@/store/authStore', () => ({
  useAuthStore: () => ({
    setTokens: vi.fn(),
    fetchUser: vi.fn().mockResolvedValue(undefined),
  }),
}))

function renderAt(path: string) {
  return render(
    <HelmetProvider>
      <MemoryRouter initialEntries={[path]}>
        <Routes>
          <Route
            path="/auth/google/callback"
            element={<OAuthCallbackPage />}
          />
          <Route
            path="/auth/microsoft/callback"
            element={<OAuthCallbackPage />}
          />
        </Routes>
      </MemoryRouter>
    </HelmetProvider>,
  )
}

describe('OAuthCallbackPage CSRF state validation', () => {
  beforeEach(() => {
    sessionStorage.clear()
    vi.clearAllMocks()
  })

  afterEach(() => {
    sessionStorage.clear()
  })

  it('shows error and does NOT call googleCallback when state in URL does not match sessionStorage', async () => {
    sessionStorage.setItem('rf-oauth-state', 'expected-state-value')

    renderAt('/auth/google/callback?code=auth-code-123&state=attacker-state')

    await waitFor(() => {
      expect(
        screen.getByText(/Invalid OAuth state/i),
      ).toBeInTheDocument()
    })

    expect(authApi.googleCallback).not.toHaveBeenCalled()
    expect(authApi.microsoftCallback).not.toHaveBeenCalled()
    // Stored value must be cleared regardless of outcome.
    expect(sessionStorage.getItem('rf-oauth-state')).toBeNull()
  })

  it('shows error and does NOT call googleCallback when stored state is missing', async () => {
    // No sessionStorage entry set.
    renderAt('/auth/google/callback?code=auth-code-123&state=any-state')

    await waitFor(() => {
      expect(
        screen.getByText(/Invalid OAuth state/i),
      ).toBeInTheDocument()
    })

    expect(authApi.googleCallback).not.toHaveBeenCalled()
  })
})
