// @vitest-environment happy-dom
import { describe, expect, it, vi } from 'vitest'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'

import { Login } from '../../views/Login.js'

/**
 * The login screen must advance to a second-factor challenge when the account
 * has MFA enabled (`onLogin` returns `requiresTOTP` + `mfaPendingToken`), and
 * must complete it via `onVerifyTotp` — including the backup-code fallback.
 */
function fillCredentials() {
  fireEvent.change(screen.getByLabelText('Email Address'), {
    target: { value: 'admin@example.com' },
  })
  fireEvent.change(screen.getByLabelText('Password'), { target: { value: 'pw' } })
}

describe('Login — MFA challenge', () => {
  it('shows the TOTP step after the password step requires it', async () => {
    const onLogin = vi.fn(async () => ({
      success: false,
      requiresTOTP: true,
      mfaPendingToken: 'pending-token',
    }))
    const onVerifyTotp = vi.fn(async () => ({ success: true }))

    render(<Login onLogin={onLogin} onVerifyTotp={onVerifyTotp} />)
    fillCredentials()
    fireEvent.click(screen.getByRole('button', { name: 'Sign In' }))

    await screen.findByText('Two-factor authentication')

    fireEvent.change(screen.getByLabelText('Authentication code'), { target: { value: '654321' } })
    fireEvent.click(screen.getByRole('button', { name: 'Verify' }))

    await waitFor(() => expect(onVerifyTotp).toHaveBeenCalledWith('pending-token', '654321'))
  })

  it('supports the backup-code fallback', async () => {
    const onLogin = vi.fn(async () => ({
      success: false,
      requiresTOTP: true,
      mfaPendingToken: 'pending-token',
    }))
    const onVerifyTotp = vi.fn(async () => ({ success: true }))

    render(<Login onLogin={onLogin} onVerifyTotp={onVerifyTotp} />)
    fillCredentials()
    fireEvent.click(screen.getByRole('button', { name: 'Sign In' }))
    await screen.findByText('Two-factor authentication')

    fireEvent.click(screen.getByRole('button', { name: 'Use a backup code' }))
    fireEvent.change(screen.getByLabelText('Backup code'), { target: { value: 'aaaa1111' } })
    fireEvent.click(screen.getByRole('button', { name: 'Verify' }))

    await waitFor(() => expect(onVerifyTotp).toHaveBeenCalledWith('pending-token', 'aaaa1111'))
  })

  it('shows an error returned from the verify step', async () => {
    const onLogin = vi.fn(async () => ({
      success: false,
      requiresTOTP: true,
      mfaPendingToken: 'pending-token',
    }))
    const onVerifyTotp = vi.fn(async () => ({ success: false, error: 'Invalid code' }))

    render(<Login onLogin={onLogin} onVerifyTotp={onVerifyTotp} />)
    fillCredentials()
    fireEvent.click(screen.getByRole('button', { name: 'Sign In' }))
    await screen.findByText('Two-factor authentication')

    fireEvent.change(screen.getByLabelText('Authentication code'), { target: { value: '000000' } })
    fireEvent.click(screen.getByRole('button', { name: 'Verify' }))

    await screen.findByText('Invalid code')
  })

  it('does not show the challenge for a normal successful login', async () => {
    const onLogin = vi.fn(async () => ({ success: true }))
    render(<Login onLogin={onLogin} />)
    fillCredentials()
    fireEvent.click(screen.getByRole('button', { name: 'Sign In' }))

    await waitFor(() => expect(onLogin).toHaveBeenCalled())
    expect(screen.queryByText('Two-factor authentication')).toBeNull()
  })
})
