"use client";

import {
  WebTypeDefinition,
  ButtonActionDefinition,
  RegistryEvent,
  WebTypeFilterOptions,
  ButtonActionFilterOptions,
} from "./types";

/**
 * 웹타입 레지스트리 클래스
 * 동적으로 웹타입 컴포넌트를 등록, 관리, 조회할 수 있는 중앙 레지스트리
 */
export class WebTypeRegistry {
  private static webTypes = new Map<string, WebTypeDefinition>();
  private static buttonActions = new Map<string, ButtonActionDefinition>();
  private static eventListeners: Array<(event: RegistryEvent) => void> = [];

  /**
   * 웹타입 등록
   */
  static registerWebType(definition: WebTypeDefinition): void {
    this.webTypes.set(definition.id, definition);
    this.emitEvent({
      type: "webtype_registered",
      data: definition,
      timestamp: new Date(),
    });
  }

  /**
   * 웹타입 등록 해제
   */
  static unregisterWebType(id: string): void {
    const definition = this.webTypes.get(id);
    if (definition) {
      this.webTypes.delete(id);
      this.emitEvent({
        type: "webtype_unregistered",
        data: definition,
        timestamp: new Date(),
      });
    }
  }

  /**
   * 웹타입 조회
   */
  static getWebType(id: string): WebTypeDefinition | undefined {
    return this.webTypes.get(id);
  }

  /**
   * 모든 웹타입 조회
   */
  static getAllWebTypes(): WebTypeDefinition[] {
    return Array.from(this.webTypes.values());
  }

  /**
   * 웹타입 필터링
   */
  static getWebTypes(options: WebTypeFilterOptions = {}): WebTypeDefinition[] {
    let webTypes = this.getAllWebTypes();

    // 활성화 상태 필터
    if (options.isActive !== undefined) {
      webTypes = webTypes.filter((wt) => wt.isActive === options.isActive);
    }

    // 카테고리 필터
    if (options.category) {
      webTypes = webTypes.filter((wt) => wt.category === options.category);
    }

    // 검색어 필터
    if (options.search) {
      const searchLower = options.search.toLowerCase();
      webTypes = webTypes.filter(
        (wt) =>
          wt.name.toLowerCase().includes(searchLower) ||
          wt.description.toLowerCase().includes(searchLower) ||
          wt.id.toLowerCase().includes(searchLower),
      );
    }

    // 태그 필터
    if (options.tags && options.tags.length > 0) {
      webTypes = webTypes.filter((wt) => wt.tags && wt.tags.some((tag) => options.tags!.includes(tag)));
    }

    return webTypes;
  }

  /**
   * 카테고리별 웹타입 그룹화
   */
  static getWebTypesByCategory(): Record<string, WebTypeDefinition[]> {
    const webTypes = this.getWebTypes({ isActive: true });
    const grouped: Record<string, WebTypeDefinition[]> = {};

    webTypes.forEach((webType) => {
      if (!grouped[webType.category]) {
        grouped[webType.category] = [];
      }
      grouped[webType.category].push(webType);
    });

    return grouped;
  }

  /**
   * 웹타입 존재 여부 확인
   */
  static hasWebType(id: string): boolean {
    return this.webTypes.has(id);
  }

  /**
   * 버튼 액션 등록
   */
  static registerButtonAction(definition: ButtonActionDefinition): void {
    this.buttonActions.set(definition.id, definition);
    this.emitEvent({
      type: "buttonaction_registered",
      data: definition,
      timestamp: new Date(),
    });
  }

  /**
   * 버튼 액션 등록 해제
   */
  static unregisterButtonAction(id: string): void {
    const definition = this.buttonActions.get(id);
    if (definition) {
      this.buttonActions.delete(id);
      this.emitEvent({
        type: "buttonaction_unregistered",
        data: definition,
        timestamp: new Date(),
      });
    }
  }

  /**
   * 버튼 액션 조회
   */
  static getButtonAction(id: string): ButtonActionDefinition | undefined {
    return this.buttonActions.get(id);
  }

  /**
   * 모든 버튼 액션 조회
   */
  static getAllButtonActions(): ButtonActionDefinition[] {
    return Array.from(this.buttonActions.values());
  }

  /**
   * 버튼 액션 필터링
   */
  static getButtonActions(options: ButtonActionFilterOptions = {}): ButtonActionDefinition[] {
    let buttonActions = this.getAllButtonActions();

    // 활성화 상태 필터
    if (options.isActive !== undefined) {
      buttonActions = buttonActions.filter((ba) => ba.isActive === options.isActive);
    }

    // 카테고리 필터
    if (options.category) {
      buttonActions = buttonActions.filter((ba) => ba.category === options.category);
    }

    // 검색어 필터
    if (options.search) {
      const searchLower = options.search.toLowerCase();
      buttonActions = buttonActions.filter(
        (ba) =>
          ba.name.toLowerCase().includes(searchLower) ||
          ba.description.toLowerCase().includes(searchLower) ||
          ba.id.toLowerCase().includes(searchLower),
      );
    }

    // 확인 필요 여부 필터
    if (options.requiresConfirmation !== undefined) {
      buttonActions = buttonActions.filter((ba) => ba.requiresConfirmation === options.requiresConfirmation);
    }

    return buttonActions;
  }

  /**
   * 이벤트 리스너 등록
   */
  static subscribe(callback: (event: RegistryEvent) => void): () => void {
    this.eventListeners.push(callback);

    // 구독 해제 함수 반환
    return () => {
      const index = this.eventListeners.indexOf(callback);
      if (index > -1) {
        this.eventListeners.splice(index, 1);
      }
    };
  }

  /**
   * 이벤트 발생
   */
  private static emitEvent(event: RegistryEvent): void {
    this.eventListeners.forEach((listener) => {
      try {
        listener(event);
      } catch (error) {
        console.error("레지스트리 이벤트 리스너 오류:", error);
      }
    });
  }

  /**
   * 레지스트리 상태 정보
   */
  static getRegistryInfo() {
    return {
      webTypesCount: this.webTypes.size,
      buttonActionsCount: this.buttonActions.size,
      activeWebTypesCount: this.getWebTypes({ isActive: true }).length,
      activeButtonActionsCount: this.getButtonActions({ isActive: true }).length,
      categories: [...new Set(this.getAllWebTypes().map((wt) => wt.category))],
      lastUpdated: new Date(),
    };
  }

  /**
   * 레지스트리 초기화 (개발/테스트용)
   */
  static clear(): void {
    this.webTypes.clear();
    this.buttonActions.clear();
    this.eventListeners.length = 0;
  }

  /**
   * 레지스트리 내용을 JSON으로 내보내기
   */
  static exportToJSON() {
    return {
      webTypes: Object.fromEntries(
        Array.from(this.webTypes.entries()).map(([id, def]) => [
          id,
          {
            ...def,
            // 함수/컴포넌트는 제외하고 메타데이터만 내보내기
            component: def.component.name || "Unknown",
            configPanel: def.configPanel.name || "Unknown",
          },
        ]),
      ),
      buttonActions: Object.fromEntries(
        Array.from(this.buttonActions.entries()).map(([id, def]) => [
          id,
          {
            ...def,
            // 함수는 제외하고 메타데이터만 내보내기
            handler: def.handler.name || "Unknown",
          },
        ]),
      ),
      exportedAt: new Date().toISOString(),
    };
  }
}
