/**
 * @moduleName: Base Component Class - Frontend Architecture Foundation
 * @version: 2.0.0
 * @since: 2025-07-23
 * @lastUpdated: 2025-07-24
 * @projectSummary: MCP Quiz Server - Base component class providing lifecycle management and event handling for all UI components
 * @techStack: TypeScript, DOM API, Event System, Component Architecture
 * @dependency: EventEmitter utility class
 * @interModuleDependency: All frontend components extend this base class
 * @requirementsTraceability:
 *   {@link Requirements.REQ_ARCH_001} (Component Integration System)
 *   {@link Requirements.REQ_UI_001} (Component Architecture Foundation)
 * @briefDescription: Abstract base class that provides common functionality for all UI components including lifecycle management, event handling, DOM manipulation, and cleanup
 * @methods: mount, unmount, render, bindEvents, onMount, onUnmount, destroy
 * @contributors: Architecture Team, GitHub Copilot
 * @examples: class MyComponent extends Component with render method implementation
 * @vulnerabilitiesAssessment: DOM element validation prevents XSS, proper event cleanup prevents memory leaks
 */

import { EventEmitter } from '../utils/index';

export abstract class Component extends EventEmitter {
  protected element: HTMLElement;
  protected mounted = false;

  /**
   * @description Creates a new component instance
   * @param {HTMLElement | string} element - DOM element or CSS selector
   * @throws {Error} If element selector is not found in DOM
   */
  constructor(element: HTMLElement | string) {
    super();
    if (typeof element === 'string') {
      const found = document.querySelector(element);
      if (!found) {
        throw new Error(`Element not found: ${element}`);
      }
      this.element = found as HTMLElement;
    } else {
      this.element = element;
    }
  }

  /**
   * @description Mounts the component to the DOM, rendering content and binding events
   * @returns {void}
   */
  mount(): void {
    if (this.mounted) return;
    this.mounted = true;
    this.render();
    this.bindEvents();
    this.onMount();
  }

  /**
   * @description Unmounts the component, cleaning up events and resources
   * @returns {void}
   */
  unmount(): void {
    if (!this.mounted) return;
    this.mounted = false;
    this.unbindEvents();
    this.onUnmount();
  }

  /**
   * @description Abstract method for rendering component content - must be implemented by subclasses
   * @returns {void}
   */
  protected abstract render(): void;

  protected bindEvents(): void {
    // Override in subclasses
  }

  protected unbindEvents(): void {
    // Override in subclasses
  }

  protected onMount(): void {
    // Override in subclasses
  }

  protected onUnmount(): void {
    // Override in subclasses
  }

  protected updateElement(
    updates: Partial<{
      innerHTML: string;
      textContent: string;
      className: string;
      hidden: boolean;
    }>
  ): void {
    if (updates.innerHTML !== undefined) {
      this.element.innerHTML = updates.innerHTML;
    }
    if (updates.textContent !== undefined) {
      this.element.textContent = updates.textContent;
    }
    if (updates.className !== undefined) {
      this.element.className = updates.className;
    }
    if (updates.hidden !== undefined) {
      this.element.hidden = updates.hidden;
    }
  }

  /**
   * @description Shows the component by removing hidden class
   * @returns {void}
   */
  show(): void {
    this.element.classList.remove('hidden');
  }

  /**
   * @description Hides the component by adding hidden class
   * @returns {void}
   */
  hide(): void {
    this.element.classList.add('hidden');
  }

  /**
   * @description Toggles component visibility
   * @param {boolean} [force] - Optional force parameter for toggle
   * @returns {void}
   */
  toggle(force?: boolean): void {
    this.element.classList.toggle('hidden', force);
  }
}
