"use client";

import { BaseLayoutRenderer, LayoutRendererProps } from "./BaseLayoutRenderer";
import { LayoutDefinition } from "@/types/layout";
import { LayoutRegistry } from "../LayoutRegistry";
import { ComponentData, LayoutComponent } from "@/types/screen";
import { LayoutZone } from "@/types/layout";
import React from "react";
import { DynamicComponentRenderer } from "../DynamicComponentRenderer";

/**
 * 자동 등록 기능을 제공하는 베이스 레이아웃 렌더러
 *
 * 사용 방법:
 * 1. 이 클래스를 상속받습니다
 * 2. static layoutDefinition을 정의합니다
 * 3. 파일을 import하면 자동으로 등록됩니다
 */
export class AutoRegisteringLayoutRenderer {
  protected props: LayoutRendererProps;

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

  /**
   * 레이아웃 정의 - 각 구현 클래스에서 반드시 정의해야 함
   */
  static readonly layoutDefinition: LayoutDefinition;

  /**
   * 렌더링 메서드 - 각 구현 클래스에서 오버라이드해야 함
   */
  render(): React.ReactElement {
    throw new Error("render() method must be implemented by subclass");
  }

  /**
   * 레이아웃 컨테이너 스타일을 계산합니다.
   */
  getLayoutContainerStyle(): React.CSSProperties {
    const { layout, style: propStyle } = this.props;

    const style: React.CSSProperties = {
      width: layout.size.width,
      height: layout.size.height,
      position: "relative",
      overflow: "hidden",
      ...propStyle,
    };

    // 레이아웃 커스텀 스타일 적용
    if (layout.style) {
      Object.assign(style, this.convertComponentStyleToCSS(layout.style));
    }

    return style;
  }

  /**
   * 컴포넌트 스타일을 CSS 스타일로 변환합니다.
   */
  protected convertComponentStyleToCSS(componentStyle: any): React.CSSProperties {
    const cssStyle: React.CSSProperties = {};

    if (componentStyle.backgroundColor) {
      cssStyle.backgroundColor = componentStyle.backgroundColor;
    }
    if (componentStyle.borderColor) {
      cssStyle.borderColor = componentStyle.borderColor;
    }
    if (componentStyle.borderWidth) {
      cssStyle.borderWidth = `${componentStyle.borderWidth}px`;
    }
    if (componentStyle.borderStyle) {
      cssStyle.borderStyle = componentStyle.borderStyle;
    }
    if (componentStyle.borderRadius) {
      cssStyle.borderRadius = `${componentStyle.borderRadius}px`;
    }

    return cssStyle;
  }

  /**
   * 존별 자식 컴포넌트들을 분류합니다.
   */
  getZoneChildren(zoneId: string): ComponentData[] {
    if (!this.props.allComponents) {
      return [];
    }

    // 1. 레이아웃 내의 존에 직접 배치된 컴포넌트들 (zoneId 기준)
    const zoneComponents = this.props.allComponents.filter(
      (comp) => comp.parentId === this.props.layout.id && comp.zoneId === zoneId,
    );

    // 2. 기존 방식 호환성 (parentId가 존 ID인 경우)
    const legacyComponents = this.props.allComponents.filter((comp) => comp.parentId === zoneId);

    // 중복 제거하여 반환
    const allComponents = [...zoneComponents, ...legacyComponents];
    const uniqueComponents = allComponents.filter(
      (component, index, array) => array.findIndex((c) => c.id === component.id) === index,
    );

    return uniqueComponents;
  }

  /**
   * 레이아웃 존을 렌더링합니다.
   */
  renderZone(
    zone: LayoutZone,
    zoneChildren: ComponentData[] = [],
    additionalProps: Record<string, any> = {},
  ): React.ReactElement {
    const { isDesignMode, onZoneClick, onComponentDrop } = this.props;

    // 존 스타일 계산 - 항상 구역 경계 표시
    const zoneStyle: React.CSSProperties = {
      position: "relative",
      // 구역 경계 시각화 - 항상 표시
      border: "1px solid #e2e8f0",
      borderRadius: "6px",
      backgroundColor: "rgba(248, 250, 252, 0.5)",
      transition: "all 0.2s ease",
      ...this.getZoneStyle(zone),
      ...additionalProps.style,
    };

    // 디자인 모드일 때 더 강조된 스타일
    if (isDesignMode) {
      zoneStyle.border = "2px dashed #cbd5e1";
      zoneStyle.backgroundColor = "rgba(241, 245, 249, 0.8)";
    }

    // 호버 효과를 위한 추가 스타일
    const dropZoneStyle: React.CSSProperties = {
      minHeight: isDesignMode ? "60px" : "40px",
      borderRadius: "4px",
      display: "flex",
      flexDirection: "column",
      alignItems: zoneChildren.length === 0 ? "center" : "stretch",
      justifyContent: zoneChildren.length === 0 ? "flex-start" : "flex-start",
      color: "#64748b",
      fontSize: "12px",
      transition: "all 0.2s ease",
      padding: "8px",
      position: "relative",
    };

    return (
      <div
        key={zone.id}
        className={`layout-zone ${additionalProps.className || ""}`}
        style={zoneStyle}
        onClick={(e) => {
          e.stopPropagation();
          onZoneClick?.(zone.id, e);
        }}
        onDragOver={(e) => {
          e.preventDefault();
          e.dataTransfer.dropEffect = "copy";
        }}
        onDrop={(e) => {
          e.preventDefault();
          const componentData = e.dataTransfer.getData("application/json");
          if (componentData) {
            try {
              const component = JSON.parse(componentData);
              onComponentDrop?.(zone.id, component, e);
            } catch (error) {
              console.error("컴포넌트 드롭 데이터 파싱 오류:", error);
            }
          }
        }}
        onMouseEnter={(e) => {
          e.currentTarget.style.borderColor = "#3b82f6";
          e.currentTarget.style.backgroundColor = "rgba(59, 130, 246, 0.05)";
          e.currentTarget.style.boxShadow = "0 0 0 2px rgba(59, 130, 246, 0.1)";
        }}
        onMouseLeave={(e) => {
          e.currentTarget.style.borderColor = isDesignMode ? "#cbd5e1" : "#e2e8f0";
          e.currentTarget.style.backgroundColor = isDesignMode
            ? "rgba(241, 245, 249, 0.8)"
            : "rgba(248, 250, 252, 0.5)";
          e.currentTarget.style.boxShadow = "none";
        }}
        {...additionalProps}
      >
        {/* 존 라벨 */}
        <div
          className="zone-label"
          style={{
            position: "absolute",
            top: "-2px",
            left: "8px",
            backgroundColor: isDesignMode ? "#3b82f6" : "#64748b",
            color: "white",
            fontSize: "10px",
            padding: "2px 6px",
            borderRadius: "0 0 4px 4px",
            fontWeight: "500",
            zIndex: 10,
            opacity: isDesignMode ? 1 : 0.7,
          }}
        >
          {zone.name || zone.id}
        </div>

        {/* 드롭존 */}
        <div
          className="drop-zone"
          style={dropZoneStyle}
          onDragOver={(e) => {
            if (isDesignMode) {
              e.preventDefault();
              e.stopPropagation();
            }
          }}
          onDrop={(e) => {
            if (isDesignMode) {
              e.preventDefault();
              e.stopPropagation();
              this.handleZoneDrop(e, zone.id);
            }
          }}
        >
          {zoneChildren.length > 0 ? (
            zoneChildren.map((child) => (
              <DynamicComponentRenderer
                key={child.id}
                component={child}
                allComponents={this.props.allComponents}
                isDesignMode={isDesignMode}
              />
            ))
          ) : (
            <div className="empty-zone-indicator" style={{ textAlign: "center", opacity: 0.6 }}>
              {isDesignMode ? "컴포넌트를 드래그하여 추가하세요" : ""}
            </div>
          )}
        </div>
      </div>
    );
  }

  /**
   * 존에 드롭된 컴포넌트를 처리합니다.
   */
  private handleZoneDrop = (e: React.DragEvent, zoneId: string) => {
    try {
      const dragData = e.dataTransfer.getData("application/json");
      if (!dragData) return;

      const { type, table, column, component } = JSON.parse(dragData);

      // 드롭 위치 계산 (존 내부 상대 좌표)
      const dropZone = e.currentTarget as HTMLElement;
      const rect = dropZone.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;

      let newComponent: any;

      if (type === "table") {
        // 테이블 컨테이너 생성
        newComponent = {
          id: `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          type: "container",
          label: table.tableLabel || table.tableName,
          tableName: table.tableName,
          position: { x, y, z: 1 },
          size: { width: 300, height: 200 },
          parentId: this.props.layout.id, // 레이아웃을 부모로 설정
          zoneId: zoneId, // 존 ID 설정
        };
      } else if (type === "column") {
        // 컬럼 위젯 생성
        newComponent = {
          id: `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          type: "widget",
          label: column.columnLabel || column.columnName,
          tableName: table.tableName,
          columnName: column.columnName,
          widgetType: column.widgetType,
          dataType: column.dataType,
          required: column.required,
          position: { x, y, z: 1 },
          size: { width: 200, height: 40 },
          parentId: this.props.layout.id, // 레이아웃을 부모로 설정
          zoneId: zoneId, // 존 ID 설정
        };
      } else if (type === "component" && component) {
        // 컴포넌트 생성
        newComponent = {
          id: `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          type: component.componentType || "widget",
          label: component.name,
          widgetType: component.webType,
          position: { x, y, z: 1 },
          size: component.defaultSize || { width: 200, height: 40 },
          parentId: this.props.layout.id, // 레이아웃을 부모로 설정
          zoneId: zoneId, // 존 ID 설정
          componentConfig: component.componentConfig || {},
          webTypeConfig: this.getDefaultWebTypeConfig(component.webType),
          style: {
            labelDisplay: true,
            labelFontSize: "14px",
            labelColor: "#212121",
            labelFontWeight: "500",
            labelMarginBottom: "4px",
          },
        };
      }

      if (newComponent && this.props.onUpdateLayout) {
        // 레이아웃에 컴포넌트 추가
        const updatedComponents = [...(this.props.layout.components || []), newComponent];
        this.props.onUpdateLayout({
          ...this.props.layout,
          components: updatedComponents,
        });

        console.log(`컴포넌트가 존 ${zoneId}에 추가되었습니다:`, newComponent);
      }
    } catch (error) {
      console.error("존 드롭 처리 중 오류:", error);
    }
  };

  /**
   * 웹타입별 기본 설정을 반환합니다.
   */
  private getDefaultWebTypeConfig = (webType: string) => {
    const configs: Record<string, any> = {
      text: { maxLength: 255 },
      number: { min: 0, max: 999999 },
      date: { format: "YYYY-MM-DD" },
      select: { options: [] },
      // 추가 웹타입 설정...
    };
    return configs[webType] || {};
  };

  /**
   * 존의 스타일을 계산합니다.
   */
  protected getZoneStyle(zone: LayoutZone): React.CSSProperties {
    const style: React.CSSProperties = {};

    if (zone.size) {
      if (zone.size.width) {
        style.width = typeof zone.size.width === "number" ? `${zone.size.width}px` : zone.size.width;
      }
      if (zone.size.height) {
        style.height = typeof zone.size.height === "number" ? `${zone.size.height}px` : zone.size.height;
      }
      if (zone.size.minWidth) {
        style.minWidth = typeof zone.size.minWidth === "number" ? `${zone.size.minWidth}px` : zone.size.minWidth;
      }
      if (zone.size.minHeight) {
        style.minHeight = typeof zone.size.minHeight === "number" ? `${zone.size.minHeight}px` : zone.size.minHeight;
      }
    }

    return style;
  }

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

  /**
   * 클래스가 정의될 때 자동으로 레지스트리에 등록
   */
  static registerSelf(): void {
    const definition = this.layoutDefinition;

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

    if (this.registeredLayouts.has(definition.id)) {
      console.warn(`⚠️ ${definition.id} 레이아웃이 이미 등록되어 있습니다.`);
      return;
    }

    try {
      // 레지스트리에 등록
      LayoutRegistry.registerLayout(definition);
      this.registeredLayouts.add(definition.id);

      console.log(`✅ 자동 등록 완료: ${definition.id} (${definition.name})`);

      // 개발 모드에서 추가 정보 출력
      if (process.env.NODE_ENV === "development") {
        console.log(`📦 ${definition.id}:`, {
          name: definition.name,
          category: definition.category,
          zones: definition.defaultZones?.length || 0,
          tags: definition.tags?.join(", ") || "none",
        });
      }
    } catch (error) {
      console.error(`❌ ${definition.id} 레이아웃 등록 실패:`, error);
    }
  }

  /**
   * 레이아웃 등록 해제 (개발 모드에서 Hot Reload용)
   */
  static unregisterSelf(): void {
    const definition = this.layoutDefinition;

    if (definition && this.registeredLayouts.has(definition.id)) {
      LayoutRegistry.unregisterLayout(definition.id);
      this.registeredLayouts.delete(definition.id);
      console.log(`🗑️ 등록 해제: ${definition.id}`);
    }
  }

  /**
   * Hot Reload 지원 (개발 모드)
   */
  static reloadSelf(): void {
    if (process.env.NODE_ENV === "development") {
      this.unregisterSelf();
      this.registerSelf();
      console.log(`🔄 Hot Reload: ${this.layoutDefinition?.id}`);
    }
  }

  /**
   * 등록된 레이아웃 목록 조회
   */
  static getRegisteredLayouts(): string[] {
    return Array.from(this.registeredLayouts);
  }

  /**
   * 레이아웃 정의 유효성 검사
   */
  static validateDefinition(): { isValid: boolean; errors: string[]; warnings: string[] } {
    const definition = this.layoutDefinition;

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

    const errors: string[] = [];
    const warnings: string[] = [];

    // 필수 필드 검사
    if (!definition.id) errors.push("ID가 필요합니다.");
    if (!definition.name) errors.push("이름이 필요합니다.");
    if (!definition.component) errors.push("컴포넌트가 필요합니다.");
    if (!definition.category) errors.push("카테고리가 필요합니다.");

    // 권장사항 검사
    if (!definition.description || definition.description.length < 10) {
      warnings.push("설명은 10자 이상 권장됩니다.");
    }
    if (!definition.defaultZones || definition.defaultZones.length === 0) {
      warnings.push("기본 존 정의가 권장됩니다.");
    }

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

/**
 * 개발 모드에서 Hot Module Replacement 지원
 */
if (process.env.NODE_ENV === "development" && typeof window !== "undefined") {
  // HMR API가 있는 경우 등록
  if ((module as any).hot) {
    (module as any).hot.accept();

    // 글로벌 Hot Reload 함수 등록
    (window as any).__reloadLayout__ = (layoutId: string) => {
      const layouts = AutoRegisteringLayoutRenderer.getRegisteredLayouts();
      console.log(`🔄 Available layouts for reload:`, layouts);

      // TODO: 특정 레이아웃만 리로드하는 로직 구현
    };
  }
}
