/**
 * @fileoverview Login Modal Component - User Authentication Interface
 * @version 1.0.0
 * @since 2025-08-04
 * @lastUpdated 2025-08-04
 * @module LoginModal
 * @description Modal component for user authentication with form validation and accessibility features
 * @contributors Claude Code Agent
 * @dependencies Component base class, AuthService, DOMUtils
 * @requirements REQ-AUTH-012 (Login UI component)
 * @testCoverage Authentication flow, form validation, accessibility compliance
 */

import { AuthService } from '../services/AuthService';
import { Component } from './Component';

export interface LoginModalOptions {
  onSuccess?: (user: any) => void;
  onCancel?: () => void;
  showRegisterLink?: boolean;
  allowGuestMode?: boolean;
}

/**
 * Login Modal Component
 *
 * @description Provides user authentication interface with form validation,
 *              accessibility features, and error handling. Follows established
 *              modal patterns from the existing codebase.
 *
 * @example
 * ```typescript
 * const loginModal = new LoginModal({
 *   onSuccess: (user) => console.log('Logged in:', user),
 *   onCancel: () => console.log('Login cancelled')
 * });
 * loginModal.show();
 * ```
 *
 * @since 2025-08-04
 * @author Claude Code Agent
 * @requirements REQ-AUTH-012 (Login modal interface)
 * @accessibility WCAG 2.1 AA compliant with focus management and screen reader support
 */
export class LoginModal extends Component {
  private authService: AuthService;
  private options: LoginModalOptions;
  private isVisible: boolean = false;
  private previousFocus: HTMLElement | null = null;
  private unsubscribeAuth: (() => void) | null = null;

  // Form elements
  private usernameInput: HTMLInputElement | null = null;
  private passwordInput: HTMLInputElement | null = null;
  private loginButton: HTMLButtonElement | null = null;
  private cancelButton: HTMLButtonElement | null = null;
  private errorContainer: HTMLElement | null = null;
  private loadingSpinner: HTMLElement | null = null;

  constructor(options: LoginModalOptions = {}) {
    // Create modal element if it doesn't exist
    if (!document.getElementById('login-modal')) {
      const modalElement = document.createElement('div');
      modalElement.id = 'login-modal';
      modalElement.className = 'fixed inset-0 z-[10000] hidden';
      document.body.appendChild(modalElement);
    }

    super('#login-modal');
    this.authService = AuthService.getInstance();
    this.options = options;
  }

  /**
   * Show the login modal
   *
   * @description Displays the login modal with proper focus management
   *              and accessibility announcements.
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Saves focus and announces modal opening to screen readers
   */
  show(): void {
    if (this.isVisible) return;

    // Save currently focused element
    this.previousFocus = document.activeElement as HTMLElement;

    this.render();
    this.bindEvents();
    this.mount();

    // Show modal with animation
    this.element.classList.remove('hidden');

    // Force reflow for animation
    this.element.offsetHeight;

    // Add visible class for animation
    const overlay = this.element.querySelector('.login-overlay');
    const modal = this.element.querySelector('.login-modal');

    if (overlay && modal) {
      overlay.classList.add('opacity-100');
      modal.classList.add('scale-100', 'opacity-100');
    }

    // Focus the username input
    setTimeout(() => {
      this.usernameInput?.focus();
    }, 150);

    this.isVisible = true;

    // Announce to screen readers
    this.announceToScreenReader('Login dialog opened');
  }

  /**
   * Hide the login modal
   *
   * @description Hides the modal with animation and restores focus
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Restores focus to previously focused element
   */
  hide(): void {
    if (!this.isVisible) return;

    const overlay = this.element.querySelector('.login-overlay');
    const modal = this.element.querySelector('.login-modal');

    if (overlay && modal) {
      overlay.classList.remove('opacity-100');
      modal.classList.remove('scale-100', 'opacity-100');
    }

    // Hide after animation
    setTimeout(() => {
      this.element.classList.add('hidden');
      this.unmount();

      // Restore focus
      if (this.previousFocus) {
        this.previousFocus.focus();
      }
    }, 300);

    this.isVisible = false;

    // Announce to screen readers
    this.announceToScreenReader('Login dialog closed');
  }

  /**
   * Render the modal content
   *
   * @description Creates the modal HTML structure with form elements,
   *              error handling, and accessibility attributes.
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  protected render(): void {
    this.element.innerHTML = `
      <div class="login-overlay fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm opacity-0 transition-all duration-300 flex items-center justify-center">
        <div class="login-modal bg-white dark:bg-gray-800 rounded-2xl shadow-2xl max-w-md w-11/12 mx-4 overflow-hidden transform scale-95 opacity-0 transition-all duration-300"
             role="dialog"
             aria-labelledby="login-title"
             aria-describedby="login-description">

          <!-- Header -->
          <div class="login-header bg-gradient-to-r from-blue-600 to-blue-700 px-6 py-4">
            <div class="flex items-center justify-between">
              <div class="flex items-center">
                <div class="login-icon text-2xl text-white mr-3">🔐</div>
                <h2 id="login-title" class="text-xl font-semibold text-white">
                  Sign In
                </h2>
              </div>
              <button type="button"
                      class="cancel-btn text-white hover:text-gray-200 transition-colors p-1 rounded focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-blue-600"
                      aria-label="Close login dialog">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                </svg>
              </button>
            </div>
          </div>

          <!-- Content -->
          <div class="login-content p-6">
            <p id="login-description" class="text-gray-600 dark:text-gray-400 mb-6 text-center">
              Sign in to access your personalized quiz experience and track your progress.
            </p>

            <!-- Error Alert -->
            <div class="error-container hidden mb-4" role="alert" aria-live="polite">
              <div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
                <div class="flex items-center">
                  <div class="error-icon text-red-500 mr-3">⚠️</div>
                  <div class="error-message text-red-700 dark:text-red-400 font-medium"></div>
                </div>
              </div>
            </div>

            <!-- Login Form -->
            <form class="login-form space-y-4">
              <!-- Username Field -->
              <div class="form-group">
                <label for="username-input" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
                  Username or Email
                </label>
                <input type="text"
                       id="username-input"
                       class="username-input w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white transition-colors"
                       placeholder="Enter your username or email"
                       required
                       autocomplete="username"
                       aria-describedby="username-help">
                <div id="username-help" class="text-xs text-gray-500 dark:text-gray-400 mt-1">
                  Use your registered username or email address
                </div>
              </div>

              <!-- Password Field -->
              <div class="form-group">
                <label for="password-input" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
                  Password
                </label>
                <div class="relative">
                  <input type="password"
                         id="password-input"
                         class="password-input w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white transition-colors pr-12"
                         placeholder="Enter your password"
                         required
                         autocomplete="current-password"
                         aria-describedby="password-help">
                  <button type="button"
                          class="password-toggle absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded p-1"
                          aria-label="Toggle password visibility">
                    <svg class="w-5 h-5 password-show" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
                    </svg>
                    <svg class="w-5 h-5 password-hide hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L12 12m-3.122-3.122l4.242 4.242M21 21l-4.24-4.24"></path>
                    </svg>
                  </button>
                </div>
                <div id="password-help" class="text-xs text-gray-500 dark:text-gray-400 mt-1">
                  Enter your account password
                </div>
              </div>

              <!-- Remember Me -->
              <div class="form-group">
                <label class="flex items-center">
                  <input type="checkbox"
                         class="remember-checkbox rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500 dark:bg-gray-700">
                  <span class="ml-2 text-sm text-gray-700 dark:text-gray-300">
                    Keep me signed in
                  </span>
                </label>
              </div>
            </form>

            <!-- Action Buttons -->
            <div class="login-actions flex flex-col space-y-3 mt-6">
              <button type="submit"
                      class="login-btn w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-6 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed">
                <span class="btn-text">Sign In</span>
                <div class="loading-spinner hidden ml-2 inline-block">
                  <svg class="animate-spin h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
                    <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                    <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                  </svg>
                </div>
              </button>

              ${
                this.options.allowGuestMode
                  ? `
                <button type="button"
                        class="guest-btn w-full bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300 font-medium py-3 px-6 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
                  Continue as Guest
                </button>
              `
                  : ''
              }
            </div>

            ${
              this.options.showRegisterLink
                ? `
              <!-- Register Link -->
              <div class="text-center mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
                <p class="text-sm text-gray-600 dark:text-gray-400">
                  Don't have an account?
                  <button type="button"
                          class="register-link text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 font-medium focus:outline-none focus:underline">
                    Create Account
                  </button>
                </p>
              </div>
            `
                : ''
            }

            <!-- Forgot Password -->
            <div class="text-center mt-4">
              <button type="button"
                      class="forgot-password-link text-sm text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 focus:outline-none focus:underline">
                Forgot your password?
              </button>
            </div>
          </div>
        </div>
      </div>
    `;

    // Cache form elements
    this.cacheElements();
  }

  /**
   * Cache form elements for efficient access
   *
   * @description Stores references to frequently accessed DOM elements
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private cacheElements(): void {
    this.usernameInput = this.element.querySelector('.username-input') as HTMLInputElement;
    this.passwordInput = this.element.querySelector('.password-input') as HTMLInputElement;
    this.loginButton = this.element.querySelector('.login-btn') as HTMLButtonElement;
    this.cancelButton = this.element.querySelector('.cancel-btn') as HTMLButtonElement;
    this.errorContainer = this.element.querySelector('.error-container') as HTMLElement;
    this.loadingSpinner = this.element.querySelector('.loading-spinner') as HTMLElement;
  }

  /**
   * Bind event listeners
   *
   * @description Sets up all event listeners for form interaction,
   *              keyboard navigation, and accessibility features.
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Includes keyboard navigation and escape key handling
   */
  protected bindEvents(): void {
    // Form submission
    const form = this.element.querySelector('.login-form') as HTMLFormElement;
    form?.addEventListener('submit', this.handleSubmit.bind(this));

    // Login button
    this.loginButton?.addEventListener('click', this.handleSubmit.bind(this));

    // Cancel button
    this.cancelButton?.addEventListener('click', this.handleCancel.bind(this));

    // Password toggle
    const passwordToggle = this.element.querySelector('.password-toggle') as HTMLButtonElement;
    passwordToggle?.addEventListener('click', this.togglePasswordVisibility.bind(this));

    // Guest mode button
    const guestButton = this.element.querySelector('.guest-btn') as HTMLButtonElement;
    guestButton?.addEventListener('click', this.handleGuestMode.bind(this));

    // Register link
    const registerLink = this.element.querySelector('.register-link') as HTMLButtonElement;
    registerLink?.addEventListener('click', this.handleRegisterLink.bind(this));

    // Forgot password link
    const forgotLink = this.element.querySelector('.forgot-password-link') as HTMLButtonElement;
    forgotLink?.addEventListener('click', this.handleForgotPassword.bind(this));

    // Keyboard navigation
    document.addEventListener('keydown', this.handleKeyDown.bind(this));

    // Click outside to close
    const overlay = this.element.querySelector('.login-overlay');
    overlay?.addEventListener('click', e => {
      if (e.target === overlay) {
        this.handleCancel();
      }
    });

    // Subscribe to auth state changes
    this.unsubscribeAuth = this.authService.subscribe(this.handleAuthStateChange.bind(this));

    // Input validation
    this.usernameInput?.addEventListener('input', this.validateForm.bind(this));
    this.passwordInput?.addEventListener('input', this.validateForm.bind(this));
  }

  /**
   * Handle form submission
   *
   * @description Processes login form submission with validation
   *              and error handling.
   *
   * @param {Event} event - Form or button click event
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private async handleSubmit(event: Event): Promise<void> {
    event.preventDefault();

    if (!this.usernameInput || !this.passwordInput) {
      this.showError('Form elements not found');
      return;
    }

    const username = this.usernameInput.value.trim();
    const password = this.passwordInput.value;

    // Client-side validation
    if (!username) {
      this.showError('Please enter your username or email');
      this.usernameInput.focus();
      return;
    }

    if (!password) {
      this.showError('Please enter your password');
      this.passwordInput.focus();
      return;
    }

    // Show loading state
    this.setLoadingState(true);
    this.hideError();

    try {
      const success = await this.authService.login({ username, password });

      if (success) {
        const authState = this.authService.getAuthState();
        this.announceToScreenReader(`Welcome back, ${authState.user?.username || 'user'}!`);

        // Call success callback
        if (this.options.onSuccess) {
          this.options.onSuccess(authState.user);
        }

        // Hide modal
        this.hide();
      }
      // Error handling is done through auth state subscription
    } catch (error) {
      console.error('Login error:', error);
      this.showError('An unexpected error occurred. Please try again.');
    } finally {
      this.setLoadingState(false);
    }
  }

  /**
   * Handle cancel button click
   *
   * @description Closes the modal and calls the cancel callback
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private handleCancel(): void {
    if (this.options.onCancel) {
      this.options.onCancel();
    }
    this.hide();
  }

  /**
   * Handle keyboard navigation
   *
   * @description Manages keyboard shortcuts and navigation within the modal
   *
   * @param {KeyboardEvent} event - Keyboard event
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Supports escape key and tab navigation
   */
  private handleKeyDown(event: KeyboardEvent): void {
    if (!this.isVisible) return;

    switch (event.key) {
      case 'Escape':
        event.preventDefault();
        this.handleCancel();
        break;

      case 'Enter':
        // Allow form submission via Enter key
        if (event.target !== this.loginButton) {
          event.preventDefault();
          this.handleSubmit(event);
        }
        break;

      case 'Tab':
        // Trap focus within modal
        this.trapFocus(event);
        break;
    }
  }

  /**
   * Trap focus within the modal
   *
   * @description Ensures tab navigation stays within the modal for accessibility
   *
   * @param {KeyboardEvent} event - Tab key event
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Implements focus trap for screen reader users
   */
  private trapFocus(event: KeyboardEvent): void {
    const focusableElements = this.element.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    ) as NodeListOf<HTMLElement>;

    const firstElement = focusableElements[0];
    const lastElement = focusableElements[focusableElements.length - 1];

    if (event.shiftKey) {
      if (document.activeElement === firstElement) {
        event.preventDefault();
        lastElement.focus();
      }
    } else {
      if (document.activeElement === lastElement) {
        event.preventDefault();
        firstElement.focus();
      }
    }
  }

  /**
   * Toggle password field visibility
   *
   * @description Shows/hides password text with proper accessibility attributes
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Updates aria-label and visual indicators
   */
  private togglePasswordVisibility(): void {
    if (!this.passwordInput) return;

    const isPassword = this.passwordInput.type === 'password';
    const toggle = this.element.querySelector('.password-toggle') as HTMLButtonElement;
    const showIcon = toggle?.querySelector('.password-show');
    const hideIcon = toggle?.querySelector('.password-hide');

    if (isPassword) {
      this.passwordInput.type = 'text';
      toggle?.setAttribute('aria-label', 'Hide password');
      showIcon?.classList.add('hidden');
      hideIcon?.classList.remove('hidden');
    } else {
      this.passwordInput.type = 'password';
      toggle?.setAttribute('aria-label', 'Show password');
      showIcon?.classList.remove('hidden');
      hideIcon?.classList.add('hidden');
    }
  }

  /**
   * Handle guest mode selection
   *
   * @description Allows users to continue without authentication
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private handleGuestMode(): void {
    this.announceToScreenReader('Continuing as guest user');

    if (this.options.onSuccess) {
      this.options.onSuccess(null); // Null indicates guest mode
    }

    this.hide();
  }

  /**
   * Handle register link click
   *
   * @description Placeholder for registration functionality
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private handleRegisterLink(): void {
    // TODO: Implement registration modal or redirect
    console.log('Registration requested');
    this.announceToScreenReader('Registration feature coming soon');
  }

  /**
   * Handle forgot password link
   *
   * @description Placeholder for password reset functionality
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private handleForgotPassword(): void {
    // TODO: Implement password reset modal or redirect
    console.log('Password reset requested');
    this.announceToScreenReader('Password reset feature coming soon');
  }

  /**
   * Handle authentication state changes
   *
   * @description Responds to auth service state updates
   *
   * @param {object} authState - Current authentication state
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private handleAuthStateChange(authState: any): void {
    if (authState.error) {
      this.showError(authState.error);
      this.setLoadingState(false);
    }

    if (authState.isLoading) {
      this.setLoadingState(true);
    } else {
      this.setLoadingState(false);
    }
  }

  /**
   * Show error message
   *
   * @description Displays error message with accessibility announcement
   *
   * @param {string} message - Error message to display
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Announces errors to screen readers
   */
  private showError(message: string): void {
    if (!this.errorContainer) return;

    const errorMessage = this.errorContainer.querySelector('.error-message');
    if (errorMessage) {
      errorMessage.textContent = message;
    }

    this.errorContainer.classList.remove('hidden');
    this.announceToScreenReader(`Error: ${message}`);
  }

  /**
   * Hide error message
   *
   * @description Hides the error container
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private hideError(): void {
    this.errorContainer?.classList.add('hidden');
  }

  /**
   * Set loading state
   *
   * @description Updates UI to show/hide loading indicators
   *
   * @param {boolean} loading - Whether to show loading state
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private setLoadingState(loading: boolean): void {
    if (!this.loginButton) return;

    const btnText = this.loginButton.querySelector('.btn-text');
    const spinner = this.loginButton.querySelector('.loading-spinner');

    if (loading) {
      this.loginButton.disabled = true;
      btnText && (btnText.textContent = 'Signing In...');
      spinner?.classList.remove('hidden');
    } else {
      this.loginButton.disabled = false;
      btnText && (btnText.textContent = 'Sign In');
      spinner?.classList.add('hidden');
    }
  }

  /**
   * Validate form inputs
   *
   * @description Performs real-time form validation
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  private validateForm(): void {
    if (!this.usernameInput || !this.passwordInput || !this.loginButton) return;

    const username = this.usernameInput.value.trim();
    const password = this.passwordInput.value;

    const isValid = username.length > 0 && password.length > 0;
    this.loginButton.disabled = !isValid;
  }

  /**
   * Announce message to screen readers
   *
   * @description Creates temporary element for screen reader announcements
   *
   * @param {string} message - Message to announce
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @accessibility Provides screen reader feedback
   */
  private announceToScreenReader(message: string): void {
    const announcement = document.createElement('div');
    announcement.setAttribute('aria-live', 'polite');
    announcement.setAttribute('aria-atomic', 'true');
    announcement.className = 'sr-only';
    announcement.textContent = message;

    document.body.appendChild(announcement);

    setTimeout(() => {
      document.body.removeChild(announcement);
    }, 1000);
  }

  /**
   * Clean up event listeners and resources
   *
   * @description Removes event listeners when component is unmounted
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  protected onUnmount(): void {
    document.removeEventListener('keydown', this.handleKeyDown.bind(this));
    this.unsubscribeAuth?.();
  }

  /**
   * Static factory method for showing login modal
   *
   * @description Convenience method for creating and showing login modal
   *
   * @param {LoginModalOptions} options - Modal configuration options
   * @returns {LoginModal} Modal instance
   *
   * @example
   * ```typescript
   * LoginModal.show({
   *   onSuccess: (user) => console.log('Logged in:', user),
   *   showRegisterLink: true
   * });
   * ```
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  static show(options: LoginModalOptions = {}): LoginModal {
    const modal = new LoginModal(options);
    modal.show();
    return modal;
  }
}
