"use client";

import React from "react";
import { ComponentDefinition, ComponentRendererProps, ComponentConfig } from "@/types/component";
import { ComponentRegistry } from "./ComponentRegistry";

/**
 * 자동 등록 컴포넌트 렌더러 기본 클래스
 * 모든 컴포넌트 렌더러가 상속받아야 하는 기본 클래스
 * 레이아웃 시스템의 AutoRegisteringLayoutRenderer와 동일한 패턴
 */
export class AutoRegisteringComponentRenderer {
  protected props: ComponentRendererProps;

  /**
   * 각 컴포넌트 렌더러에서 반드시 정의해야 하는 컴포넌트 정의
   * 이 정의를 바탕으로 자동 등록이 수행됩니다
   */
  static componentDefinition: ComponentDefinition;

  constructor(props: ComponentRendererProps) {
    this.props = props;
  }

  /**
   * 컴포넌트 렌더링 메서드
   * 각 렌더러에서 반드시 구현해야 합니다
   */
  render(): React.ReactElement {
    throw new Error(`${this.constructor.name}: render() 메서드를 구현해야 합니다. 이는 추상 메서드입니다.`);
  }

  /**
   * 공통 컴포넌트 스타일 생성
   * 위치, 크기 등의 기본 스타일을 자동으로 계산합니다
   */
  protected getComponentStyle(): React.CSSProperties {
    const { component, isDesignMode = false } = this.props;

    const baseStyle: React.CSSProperties = {
      position: "absolute",
      left: `${component.position?.x || 0}px`,
      top: `${component.position?.y || 0}px`,
      width: `${component.size?.width || 200}px`,
      height: `${component.size?.height || 36}px`,
      zIndex: component.position?.z || 1,
      ...component.style,
    };

    // 디자인 모드에서 추가 스타일
    if (isDesignMode) {
      baseStyle.border = "1px dashed #cbd5e1";
      baseStyle.borderColor = this.props.isSelected ? "#3b82f6" : "#cbd5e1";
    }

    return baseStyle;
  }

  /**
   * 웹타입에 따른 Props 생성
   * 각 웹타입별로 적절한 HTML 속성들을 자동으로 생성합니다
   */
  protected getWebTypeProps(): Record<string, any> {
    const { component } = this.props;

    const baseProps = {
      id: component.id,
      name: component.id,
      value: component.value || "",
      disabled: component.readonly || false,
      required: component.required || false,
      placeholder: component.placeholder || "",
    };

    switch (component.webType) {
      case "text":
        return {
          ...baseProps,
          type: "text",
          maxLength: component.maxLength,
          minLength: component.minLength,
        };

      case "number":
        return {
          ...baseProps,
          type: "number",
          min: component.min,
          max: component.max,
          step: component.step || 1,
        };

      case "email":
        return {
          ...baseProps,
          type: "email",
        };

      case "password":
        return {
          ...baseProps,
          type: "password",
        };

      case "date":
        return {
          ...baseProps,
          type: "date",
          min: component.minDate,
          max: component.maxDate,
        };

      case "datetime":
        return {
          ...baseProps,
          type: "datetime-local",
          min: component.minDate,
          max: component.maxDate,
        };

      case "time":
        return {
          ...baseProps,
          type: "time",
        };

      case "url":
        return {
          ...baseProps,
          type: "url",
        };

      case "tel":
        return {
          ...baseProps,
          type: "tel",
        };

      case "search":
        return {
          ...baseProps,
          type: "search",
        };

      case "textarea":
        return {
          ...baseProps,
          rows: component.rows || 3,
          cols: component.cols,
          wrap: component.wrap || "soft",
        };

      case "select":
      case "dropdown":
        return {
          ...baseProps,
          multiple: component.multiple || false,
        };

      case "checkbox":
        return {
          ...baseProps,
          type: "checkbox",
          checked: component.checked || false,
        };

      case "radio":
        return {
          ...baseProps,
          type: "radio",
          checked: component.checked || false,
        };

      case "button":
        return {
          ...baseProps,
          type: component.buttonType || "button",
        };

      case "file":
        return {
          ...baseProps,
          type: "file",
          accept: component.accept,
          multiple: component.multiple || false,
        };

      case "range":
        return {
          ...baseProps,
          type: "range",
          min: component.min || 0,
          max: component.max || 100,
          step: component.step || 1,
        };

      case "color":
        return {
          ...baseProps,
          type: "color",
        };

      default:
        return baseProps;
    }
  }

  /**
   * 라벨 스타일 생성 헬퍼
   * 라벨이 있는 컴포넌트들을 위한 공통 라벨 스타일 생성
   */
  protected getLabelStyle(): React.CSSProperties {
    const { component } = this.props;

    return {
      position: "absolute",
      top: "-25px",
      left: "0px",
      fontSize: component.style?.labelFontSize || "14px",
      color: component.style?.labelColor || "#212121",
      marginBottom: component.style?.labelMarginBottom || "4px",
      fontWeight: "500",
    };
  }

  /**
   * 라벨 정보 반환
   */
  protected getLabelInfo(): { text: string; isRequired: boolean } | null {
    const { component } = this.props;

    if (!component.label && !component.style?.labelText) {
      return null;
    }

    return {
      text: component.style?.labelText || component.label,
      isRequired: component.required || false,
    };
  }

  /**
   * 오류 스타일 생성 헬퍼
   */
  protected getErrorStyle(): React.CSSProperties {
    return {
      position: "absolute",
      top: "100%",
      left: "0px",
      fontSize: "12px",
      color: "#ef4444",
      marginTop: "4px",
    };
  }

  /**
   * 도움말 텍스트 스타일 생성 헬퍼
   */
  protected getHelperTextStyle(): React.CSSProperties {
    return {
      position: "absolute",
      top: "100%",
      left: "0px",
      fontSize: "12px",
      color: "#6b7280",
      marginTop: "4px",
    };
  }

  /**
   * 이벤트 핸들러 생성
   * 공통적으로 사용되는 이벤트 핸들러들을 생성합니다
   */
  protected getEventHandlers() {
    const { onClick, onDragStart, onDragEnd } = this.props;

    return {
      onClick: (e: React.MouseEvent) => {
        e.stopPropagation();
        onClick?.();
      },
      onDragStart: (e: React.DragEvent) => {
        onDragStart?.(e);
      },
      onDragEnd: (e: React.DragEvent) => {
        onDragEnd?.(e);
      },
    };
  }

  /**
   * 컴포넌트 설정 접근 헬퍼
   */
  protected getConfig<T = ComponentConfig>(): T {
    const { component } = this.props;
    const definition = ComponentRegistry.getComponent(component.componentType);

    return {
      ...definition?.defaultConfig,
      ...component.config,
    } as T;
  }

  /**
   * 업데이트 헬퍼
   */
  protected updateComponent(updates: Partial<any>): void {
    this.props.onUpdate?.(updates);
  }

  /**
   * 값 변경 헬퍼
   */
  protected handleValueChange(value: any): void {
    this.updateComponent({ value });
  }

  /**
   * 자동 등록 상태 추적
   */
  private static registeredComponents = new Set<string>();

  /**
   * 클래스가 정의될 때 자동으로 레지스트리에 등록
   * 레이아웃 시스템과 동일한 방식
   */
  static registerSelf(): void {
    const definition = this.componentDefinition;

    if (!definition) {
      console.error(`❌ ${this.name}: componentDefinition이 정의되지 않았습니다.`);
      return;
    }

    if (this.registeredComponents.has(definition.id)) {
      return;
    }

    try {
      // 레지스트리에 등록
      ComponentRegistry.registerComponent(definition);
      this.registeredComponents.add(definition.id);
    } catch (error) {
      console.error(`❌ ${definition.id} 컴포넌트 등록 실패:`, error);
    }
  }

  /**
   * 컴포넌트 등록 해제 (개발 모드에서 Hot Reload용)
   */
  static unregisterSelf(): void {
    const definition = this.componentDefinition;
    if (definition && this.registeredComponents.has(definition.id)) {
      ComponentRegistry.unregisterComponent(definition.id);
      this.registeredComponents.delete(definition.id);
      console.log(`🗑️ 컴포넌트 자동 해제: ${definition.id}`);
    }
  }

  /**
   * 개발 모드에서 Hot Reload 지원
   */
  static enableHotReload(): void {
    if (process.env.NODE_ENV === "development" && typeof window !== "undefined") {
      // HMR (Hot Module Replacement) 감지
      if ((module as any).hot) {
        (module as any).hot.dispose(() => {
          this.unregisterSelf();
        });

        (module as any).hot.accept(() => {
          this.registerSelf();
        });
      }
    }
  }

  /**
   * 컴포넌트 정의 검증
   */
  static validateDefinition(): {
    isValid: boolean;
    errors: string[];
    warnings: string[];
  } {
    const definition = this.componentDefinition;

    if (!definition) {
      return {
        isValid: false,
        errors: ["componentDefinition이 정의되지 않았습니다"],
        warnings: [],
      };
    }

    // 기본적인 검증만 수행
    const errors: string[] = [];
    const warnings: string[] = [];

    if (!definition.id) errors.push("id가 필요합니다");
    if (!definition.name) errors.push("name이 필요합니다");
    if (!definition.category) errors.push("category가 필요합니다");

    return {
      isValid: errors.length === 0,
      errors,
      warnings,
    };
  }

  /**
   * 개발자 도구용 디버그 정보
   */
  static getDebugInfo(): object {
    const definition = this.componentDefinition;

    return {
      className: this.name,
      definition: definition || null,
      isRegistered: definition ? ComponentRegistry.hasComponent(definition.id) : false,
      validation: this.validateDefinition(),
    };
  }
}

// 클래스가 정의되는 즉시 자동 등록 활성화
// 하위 클래스에서 이 클래스를 상속받으면 자동으로 등록됩니다
if (typeof window !== "undefined") {
  // 브라우저 환경에서만 실행
  setTimeout(() => {
    // 모든 모듈이 로드된 후 등록 실행
    const subclasses = Object.getOwnPropertyNames(window)
      .map((name) => (window as any)[name])
      .filter(
        (obj) =>
          typeof obj === "function" &&
          obj.prototype instanceof AutoRegisteringComponentRenderer &&
          obj.componentDefinition,
      );

    subclasses.forEach((cls) => {
      try {
        cls.registerSelf();
      } catch (error) {
        console.error(`컴포넌트 자동 등록 실패: ${cls.name}`, error);
      }
    });
  }, 0);
}
