/**
 * 이벤트 관리 모듈 (EventManager.js)
 * ========================================
 * 이벤트 리스너를 중앙에서 관리합니다.
 * 리스너 ID를 저장해두면 나중에 off()로 제거 가능 (메모리 누수 방지).
 *
 * [초보자용] 전역 변수 eventManager 로 사용:
 *   eventManager.on(element, 'click', handler)
 *   eventManager.delegate(parent, 'click', '.btn', handler)
 *
 * @module EventManager
 */
class EventManager {
  constructor() {
    this.listeners = new Map();
    this.delegatedListeners = new Map();
  }

  /**
   * 이벤트 리스너 등록
   * @param {Element|Window|Document} target - 대상 요소
   * @param {string} eventType - 이벤트 타입
   * @param {Function} handler - 핸들러 함수
   * @param {Object} options - 이벤트 옵션
   * @returns {string} 리스너 ID
   */
  on(target, eventType, handler, options = {}) {
    if (!target || typeof handler !== 'function') {
      console.warn('[EventManager] Invalid target or handler');
      return null;
    }

    const listenerId = this._generateId();
    const wrappedHandler = this._wrapHandler(handler, listenerId);

    target.addEventListener(eventType, wrappedHandler, options);

    if (!this.listeners.has(target)) {
      this.listeners.set(target, new Map());
    }
    this.listeners.get(target).set(listenerId, {
      eventType,
      handler: wrappedHandler,
      originalHandler: handler,
      options,
    });

    return listenerId;
  }

  /**
   * 이벤트 리스너 제거
   * @param {Element|Window|Document} target - 대상 요소
   * @param {string} listenerId - 리스너 ID
   */
  off(target, listenerId) {
    if (!target || !listenerId) return;

    const targetListeners = this.listeners.get(target);
    if (!targetListeners) return;

    const listener = targetListeners.get(listenerId);
    if (!listener) return;

    target.removeEventListener(listener.eventType, listener.handler, listener.options);
    targetListeners.delete(listenerId);

    if (targetListeners.size === 0) {
      this.listeners.delete(target);
    }
  }

  /**
   * 이벤트 위임 등록
   * @param {Element|Window|Document} parent - 부모 요소
   * @param {string} eventType - 이벤트 타입
   * @param {string} selector - 자식 선택자
   * @param {Function} handler - 핸들러 함수
   * @param {Object} options - 이벤트 옵션
   * @returns {string} 리스너 ID
   */
  delegate(parent, eventType, selector, handler, options = {}) {
    if (!parent || typeof handler !== 'function') {
      console.warn('[EventManager] Invalid parent or handler');
      return null;
    }

    const listenerId = this._generateId();
    const wrappedHandler = (event) => {
      const target = event.target.closest(selector);
      if (target && parent.contains(target)) {
        handler.call(target, event);
      }
    };

    parent.addEventListener(eventType, wrappedHandler, options);

    if (!this.delegatedListeners.has(parent)) {
      this.delegatedListeners.set(parent, new Map());
    }
    this.delegatedListeners.get(parent).set(listenerId, {
      eventType,
      selector,
      handler: wrappedHandler,
      originalHandler: handler,
      options,
    });

    return listenerId;
  }

  /**
   * 이벤트 위임 제거
   * @param {Element|Window|Document} parent - 부모 요소
   * @param {string} listenerId - 리스너 ID
   */
  undelegate(parent, listenerId) {
    if (!parent || !listenerId) return;

    const delegatedListeners = this.delegatedListeners.get(parent);
    if (!delegatedListeners) return;

    const listener = delegatedListeners.get(listenerId);
    if (!listener) return;

    parent.removeEventListener(listener.eventType, listener.handler, listener.options);
    delegatedListeners.delete(listenerId);

    if (delegatedListeners.size === 0) {
      this.delegatedListeners.delete(parent);
    }
  }

  /**
   * 특정 요소의 모든 리스너 제거
   * @param {Element|Window|Document} target - 대상 요소
   */
  removeAll(target) {
    // 일반 리스너 제거
    const targetListeners = this.listeners.get(target);
    if (targetListeners) {
      targetListeners.forEach((listener, listenerId) => {
        target.removeEventListener(listener.eventType, listener.handler, listener.options);
      });
      this.listeners.delete(target);
    }

    // 위임 리스너 제거
    const delegatedListeners = this.delegatedListeners.get(target);
    if (delegatedListeners) {
      delegatedListeners.forEach((listener, listenerId) => {
        target.removeEventListener(listener.eventType, listener.handler, listener.options);
      });
      this.delegatedListeners.delete(target);
    }
  }

  /**
   * 모든 리스너 제거
   */
  removeAllListeners() {
    // 일반 리스너 제거
    this.listeners.forEach((targetListeners, target) => {
      targetListeners.forEach((listener) => {
        target.removeEventListener(listener.eventType, listener.handler, listener.options);
      });
    });
    this.listeners.clear();

    // 위임 리스너 제거
    this.delegatedListeners.forEach((delegatedListeners, parent) => {
      delegatedListeners.forEach((listener) => {
        parent.removeEventListener(listener.eventType, listener.handler, listener.options);
      });
    });
    this.delegatedListeners.clear();
  }

  /**
   * 한 번만 실행되는 이벤트 리스너
   * @param {Element|Window|Document} target - 대상 요소
   * @param {string} eventType - 이벤트 타입
   * @param {Function} handler - 핸들러 함수
   * @param {Object} options - 이벤트 옵션
   * @returns {string} 리스너 ID
   */
  once(target, eventType, handler, options = {}) {
    const listenerId = this._generateId();
    const wrappedHandler = (event) => {
      handler(event);
      this.off(target, listenerId);
    };

    return this.on(target, eventType, wrappedHandler, options);
  }

  /**
   * 이벤트 발생 (커스텀 이벤트)
   * @param {Element|Window|Document} target - 대상 요소
   * @param {string} eventType - 이벤트 타입
   * @param {Object} detail - 이벤트 데이터
   */
  emit(target, eventType, detail = {}) {
    if (!target) return;

    const event = new CustomEvent(eventType, {
      detail,
      bubbles: true,
      cancelable: true,
    });

    target.dispatchEvent(event);
  }

  /**
   * 핸들러 래핑 (에러 처리 포함)
   * @private
   */
  _wrapHandler(handler, listenerId) {
    return (event) => {
      try {
        handler(event);
      } catch (error) {
        console.error(`[EventManager] Error in event handler (${listenerId}):`, error);
        if (typeof ErrorHandler !== 'undefined') {
          ErrorHandler.handle(error, { context: 'EventManager', listenerId });
        }
      }
    };
  }

  /**
   * 고유 ID 생성
   * @private
   */
  _generateId() {
    return `listener_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * 등록된 리스너 정보 가져오기
   * @returns {Object}
   */
  getListenersInfo() {
    const info = {
      regular: {},
      delegated: {},
    };

    this.listeners.forEach((targetListeners, target) => {
      const targetKey = target === window ? 'window' : 
                       target === document ? 'document' : 
                       target.id || target.className || 'unknown';
      info.regular[targetKey] = Array.from(targetListeners.keys());
    });

    this.delegatedListeners.forEach((delegatedListeners, parent) => {
      const parentKey = parent === window ? 'window' : 
                       parent === document ? 'document' : 
                       parent.id || parent.className || 'unknown';
      info.delegated[parentKey] = Array.from(delegatedListeners.keys());
    });

    return info;
  }
}

/**
 * 전역 EventManager 인스턴스 (싱글톤)
 */
const eventManager = new EventManager();

// ES6 모듈 내보내기
if (typeof module !== "undefined" && module.exports) {
  module.exports = { EventManager, eventManager };
}
