import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import IdentityCheckOverlay from '@/components/IdentityCheckOverlay'
import { inventoryApi } from '@/lib/api'
import * as toast from 'react-hot-toast'

vi.mock('@/lib/api')
vi.mock('react-hot-toast')

// ============================================================================
// HELPER: Render with Props
// ============================================================================

const renderIdentityCheckOverlay = (props = {}) => {
  const defaultProps = {
    show: true,
    users: [
      { id: 1, username: 'admin', email: 'admin@test.com' },
      { id: 2, username: 'operator', email: 'op@test.com' },
    ],
    onAuthenticated: vi.fn(),
    ...props,
  }
  return render(<IdentityCheckOverlay {...defaultProps} />)
}

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

  // ============================================================================
  // UNIT TESTS: Rendering & Visibility
  // ============================================================================

  describe('Rendering', () => {
    it('should render overlay when show is true', () => {
      const { container } = renderIdentityCheckOverlay({ show: true })
      expect(container).toBeInTheDocument()
    })

    it('should not render when show is false', () => {
      const { container } = renderIdentityCheckOverlay({ show: false })
      expect(container.querySelector('.fixed')).not.toBeInTheDocument()
    })

    it('should display overlay title', () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container.textContent).toContain('Protocol Access')
    })

    it('should display overlay subtitle', () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container.textContent).toContain('Select operator')
    })
  })

  // ============================================================================
  // UNIT TESTS: User List Rendering
  // ============================================================================

  describe('User Selection', () => {
    it('should render user buttons', () => {
      const users = [
        { id: 1, username: 'admin', email: 'admin@test.com' },
        { id: 2, username: 'operator', email: 'op@test.com' },
      ]
      const { container } = renderIdentityCheckOverlay({ users })
      expect(container.textContent).toContain('admin')
      expect(container.textContent).toContain('operator')
    })

    it('should display user names in buttons', () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container.textContent).toContain('admin')
    })

    it('should handle empty user list', () => {
      const { container } = renderIdentityCheckOverlay({ users: [] })
      expect(container).toBeInTheDocument()
    })

    it('should render with single user', () => {
      const { container } = renderIdentityCheckOverlay({
        users: [{ id: 1, username: 'solo', email: 'solo@test.com' }],
      })
      expect(container.textContent).toContain('solo')
    })
  })

  // ============================================================================
  // UNIT TESTS: Login Form Rendering
  // ============================================================================

  describe('Login Form', () => {
    it('should render overlay container with proper styling', () => {
      const { container } = renderIdentityCheckOverlay()
      const modal = container.querySelector('.rounded-\\[2\\.5rem\\]')
      expect(modal || container.querySelector('[style*="border"]')).toBeTruthy()
    })

    it('should handle user selection for local login', async () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should show password input after user selection', async () => {
      const { container } = renderIdentityCheckOverlay()
      const buttons = container.querySelectorAll('button')
      expect(buttons.length).toBeGreaterThan(0)
    })

    it('should display enterprise login option', () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: Form Validation
  // ============================================================================

  describe('Form Validation', () => {
    it('should require username for enterprise login', async () => {
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(container).toBeInTheDocument()
    })

    it('should require password for local user login', async () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should show error message for empty username', async () => {
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should show error message for invalid credentials', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Invalid credentials')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: LDAP Authentication Flow
  // ============================================================================

  describe('LDAP Authentication', () => {
    it('should handle LDAP login request', async () => {
      vi.mocked(inventoryApi.login).mockResolvedValue({
        id: 1,
        username: 'enterprise_user',
        token: 'mock-token',
      })
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(container).toBeInTheDocument()
    })

    it('should handle LDAP authentication errors', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('LDAP server unreachable')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should handle group membership validation', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('User not in authorized group')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: Token Storage
  // ============================================================================

  describe('Token Storage & Callback', () => {
    it('should call onAuthenticated with user data on successful login', async () => {
      const mockUser = {
        id: 1,
        username: 'testuser',
        token: 'mock-jwt-token',
      }
      vi.mocked(inventoryApi.login).mockResolvedValue(mockUser)
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(container).toBeInTheDocument()
    })

    it('should clear selected user state after authentication', async () => {
      const mockUser = {
        id: 1,
        username: 'operator',
        token: 'token-123',
      }
      vi.mocked(inventoryApi.login).mockResolvedValue(mockUser)
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should preserve token through authentication', async () => {
      const mockUser = {
        id: 1,
        username: 'admin',
        token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
      }
      vi.mocked(inventoryApi.login).mockResolvedValue(mockUser)
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: Error Handling
  // ============================================================================

  describe('Error Handling', () => {
    it('should display error toast on login failure', async () => {
      const toastErrorSpy = vi.spyOn(toast, 'default').mockImplementation(vi.fn())
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Login failed')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should handle network errors during login', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Network error')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should handle invalid password for local user', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Invalid password')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should show different error message for enterprise vs local', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Authentication failed')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })

    it('should handle API timeout during login', async () => {
      vi.mocked(inventoryApi.login).mockImplementation(
        () => new Promise((_, reject) =>
          setTimeout(() => reject(new Error('Timeout')), 100)
        )
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container).toBeInTheDocument()
    })
  })

  // ============================================================================
  // UNIT TESTS: Accessibility
  // ============================================================================

  describe('Accessibility', () => {
    it('should have proper modal structure', () => {
      const { container } = renderIdentityCheckOverlay()
      const modal = container.querySelector('.fixed')
      expect(modal).toBeInTheDocument()
    })

    it('should have button elements with proper semantics', () => {
      const { container } = renderIdentityCheckOverlay()
      const buttons = container.querySelectorAll('button')
      expect(buttons.length).toBeGreaterThan(0)
    })

    it('should have focusable form inputs', () => {
      const { container } = renderIdentityCheckOverlay()
      const inputs = container.querySelectorAll('input')
      inputs.forEach(input => {
        expect(input).toBeInTheDocument()
      })
    })

    it('should have proper icon semantics', () => {
      const { container } = renderIdentityCheckOverlay()
      const svgs = container.querySelectorAll('svg')
      expect(svgs.length).toBeGreaterThan(0)
    })
  })

  // ============================================================================
  // UNIT TESTS: State Management
  // ============================================================================

  describe('State Management', () => {
    it('should reset form state after login', async () => {
      vi.mocked(inventoryApi.login).mockResolvedValue({
        id: 1,
        username: 'user',
        token: 'token',
      })
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(container).toBeInTheDocument()
    })

    it('should maintain user list between renders', () => {
      const users = [
        { id: 1, username: 'user1', email: 'user1@test.com' },
        { id: 2, username: 'user2', email: 'user2@test.com' },
      ]
      const { container, rerender } = renderIdentityCheckOverlay({ users })
      expect(container.textContent).toContain('user1')
      expect(container.textContent).toContain('user2')
    })
  })

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