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 })
      const overlay = container.querySelector('.fixed')
      expect(overlay).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 clickable buttons', () => {
      const { container } = renderIdentityCheckOverlay()
      const buttons = container.querySelectorAll('button')
      const userButtons = Array.from(buttons).filter(btn =>
        btn.textContent?.includes('admin')
      )
      expect(userButtons.length).toBeGreaterThan(0)
    })

    it('should render with empty user list', () => {
      const { container } = renderIdentityCheckOverlay({ users: [] })
      const modal = container.querySelector('.fixed')
      expect(modal).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 form with proper modal structure', () => {
      const { container } = renderIdentityCheckOverlay()
      const modal = container.querySelector('.fixed')
      expect(modal).toBeInTheDocument()
    })

    it('should render local login options for users', async () => {
      const { container } = renderIdentityCheckOverlay()
      const users = container.querySelectorAll('button')
      expect(users.length).toBeGreaterThan(0)
    })

    it('should have interactive form elements', async () => {
      const { container } = renderIdentityCheckOverlay()
      const buttons = container.querySelectorAll('button')
      buttons.forEach(btn => {
        expect(btn).toHaveProperty('onclick')
      })
    })

    it('should display login options', () => {
      const { container } = renderIdentityCheckOverlay()
      const modal = container.querySelector('.fixed')
      expect(modal?.textContent).toContain('Protocol Access')
    })
  })

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

  describe('Form Validation', () => {
    it('should render form with username/password inputs', async () => {
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      const inputs = container.querySelectorAll('input')
      expect(inputs.length).toBeGreaterThanOrEqual(0)
    })

    it('should render user selection for local login', async () => {
      const { container } = renderIdentityCheckOverlay()
      const users = container.textContent
      expect(users).toContain('admin')
    })

    it('should render form fields in overlay', async () => {
      const { container } = renderIdentityCheckOverlay()
      const modal = container.querySelector('.fixed')
      expect(modal).toBeInTheDocument()
    })

    it('should handle API rejection on invalid credentials', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Invalid credentials')
      )
      const { container } = renderIdentityCheckOverlay()
      const overlay = container.querySelector('.fixed')
      expect(overlay).toBeInTheDocument()
    })
  })

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

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

    it('should render form even if LDAP server is unavailable', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('LDAP server unreachable')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container.querySelector('.fixed')).toBeInTheDocument()
    })

    it('should render form if user lacks group membership', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('User not in authorized group')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container.querySelector('.fixed')).toBeInTheDocument()
    })
  })

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

  describe('Token Storage & Callback', () => {
    it('should pass onAuthenticated callback to component', 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(onAuthenticated).toBeDefined()
    })

    it('should render with mock authentication response', async () => {
      const mockUser = {
        id: 1,
        username: 'operator',
        token: 'token-123',
      }
      vi.mocked(inventoryApi.login).mockResolvedValue(mockUser)
      const { container } = renderIdentityCheckOverlay()
      expect(container.querySelector('.fixed')).toBeInTheDocument()
    })

    it('should render with JWT token mock', async () => {
      const mockUser = {
        id: 1,
        username: 'admin',
        token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
      }
      vi.mocked(inventoryApi.login).mockResolvedValue(mockUser)
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(onAuthenticated).toBeDefined()
    })
  })

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

  describe('Error Handling', () => {
    it('should render form even if login API fails', async () => {
      const toastDefaultSpy = vi.spyOn(toast, 'default').mockImplementation(vi.fn())
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Login failed')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container.querySelector('.fixed')).toBeInTheDocument()
      toastDefaultSpy.mockRestore()
    })

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

    it('should render form on invalid password', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Invalid password')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container.querySelector('.fixed')).toBeInTheDocument()
    })

    it('should render form on auth failure', async () => {
      vi.mocked(inventoryApi.login).mockRejectedValue(
        new Error('Authentication failed')
      )
      const { container } = renderIdentityCheckOverlay()
      expect(container.querySelector('.fixed')).toBeInTheDocument()
    })

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

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

  describe('Accessibility', () => {
    it('should render proper modal structure', () => {
      const { container } = renderIdentityCheckOverlay()
      const modal = container.querySelector('.fixed')
      expect(modal?.className).toContain('fixed')
    })

    it('should have interactive button elements', () => {
      const { container } = renderIdentityCheckOverlay()
      const buttons = container.querySelectorAll('button')
      expect(buttons.length).toBeGreaterThan(0)
      buttons.forEach(btn => expect(btn).toHaveProperty('click'))
    })

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

    it('should render icons in interface', () => {
      const { container } = renderIdentityCheckOverlay()
      const svgs = container.querySelectorAll('svg')
      expect(svgs.length).toBeGreaterThanOrEqual(0)
    })
  })

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

  describe('State Management', () => {
    it('should render form with auth callback', async () => {
      vi.mocked(inventoryApi.login).mockResolvedValue({
        id: 1,
        username: 'user',
        token: 'token',
      })
      const onAuthenticated = vi.fn()
      const { container } = renderIdentityCheckOverlay({ onAuthenticated })
      expect(onAuthenticated).toBeDefined()
    })

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

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