/**
 * 개선된 폼 데이터 저장 서비스
 * 클라이언트 측 사전 검증과 서버 측 검증을 조합한 안전한 저장 로직
 */

import { ComponentData, ColumnInfo, ScreenDefinition } from "@/types/screen";
import { validateFormData, ValidationResult } from "@/lib/utils/formValidation";
import { dynamicFormApi } from "@/lib/api/dynamicForm";
import { tableManagementApi } from "@/lib/api/tableManagement";
import { screenApi } from "@/lib/api/screen";

// 저장 결과 타입
export interface EnhancedSaveResult {
  success: boolean;
  message: string;
  data?: any;
  validationResult?: ValidationResult;
  performance?: {
    validationTime: number;
    saveTime: number;
    totalTime: number;
  };
  warnings?: string[];
}

// 저장 옵션
export interface SaveOptions {
  skipClientValidation?: boolean;
  skipServerValidation?: boolean;
  transformData?: boolean;
  showProgress?: boolean;
  retryOnError?: boolean;
  maxRetries?: number;
}

// 저장 컨텍스트
export interface SaveContext {
  tableName: string;
  screenInfo: ScreenDefinition;
  components: ComponentData[];
  formData: Record<string, any>;
  options?: SaveOptions;
}

/**
 * 향상된 폼 데이터 저장 클래스
 */
export class EnhancedFormService {
  private static instance: EnhancedFormService;
  private columnCache = new Map<string, ColumnInfo[]>();
  private validationCache = new Map<string, ValidationResult>();

  public static getInstance(): EnhancedFormService {
    if (!EnhancedFormService.instance) {
      EnhancedFormService.instance = new EnhancedFormService();
    }
    return EnhancedFormService.instance;
  }

  /**
   * 메인 저장 메서드
   */
  async saveFormData(context: SaveContext): Promise<EnhancedSaveResult> {
    const startTime = performance.now();
    let validationTime = 0;
    let saveTime = 0;

    try {
      const { tableName, screenInfo, components, formData, options = {} } = context;

      console.log("🚀 향상된 폼 저장 시작:", {
        tableName,
        screenId: screenInfo.screenId,
        dataKeys: Object.keys(formData),
        componentsCount: components.length,
      });

      // 1. 사전 검증 수행
      let validationResult: ValidationResult | undefined;
      if (!options.skipClientValidation) {
        const validationStart = performance.now();
        validationResult = await this.performClientValidation(formData, components, tableName);
        validationTime = performance.now() - validationStart;

        if (!validationResult.isValid) {
          console.error("❌ 클라이언트 검증 실패:", validationResult.errors);
          return {
            success: false,
            message: this.formatValidationMessage(validationResult),
            validationResult,
            performance: {
              validationTime,
              saveTime: 0,
              totalTime: performance.now() - startTime,
            },
          };
        }
      }

      // 2. 데이터 변환 및 정제
      let processedData = formData;
      if (options.transformData !== false) {
        processedData = await this.transformFormData(formData, components, tableName);
      }

      // 3. 서버 저장 수행
      const saveStart = performance.now();
      const saveResult = await this.performServerSave(screenInfo.screenId, tableName, processedData, options);
      saveTime = performance.now() - saveStart;

      if (!saveResult.success) {
        console.error("❌ 서버 저장 실패:", saveResult.message);
        return {
          success: false,
          message: saveResult.message || "저장 중 서버 오류가 발생했습니다.",
          data: saveResult.data,
          validationResult,
          performance: {
            validationTime,
            saveTime,
            totalTime: performance.now() - startTime,
          },
        };
      }

      console.log("✅ 폼 저장 성공:", {
        validationTime: `${validationTime.toFixed(2)}ms`,
        saveTime: `${saveTime.toFixed(2)}ms`,
        totalTime: `${(performance.now() - startTime).toFixed(2)}ms`,
      });

      return {
        success: true,
        message: "데이터가 성공적으로 저장되었습니다.",
        data: saveResult.data,
        validationResult,
        performance: {
          validationTime,
          saveTime,
          totalTime: performance.now() - startTime,
        },
        warnings: validationResult?.warnings.map((w) => w.message),
      };
    } catch (error: any) {
      console.error("❌ 폼 저장 중 예외 발생:", error);

      return {
        success: false,
        message: `저장 중 오류가 발생했습니다: ${error.message || error}`,
        performance: {
          validationTime,
          saveTime,
          totalTime: performance.now() - startTime,
        },
      };
    }
  }

  /**
   * 클라이언트 측 검증 수행
   */
  private async performClientValidation(
    formData: Record<string, any>,
    components: ComponentData[],
    tableName: string,
  ): Promise<ValidationResult> {
    try {
      // 캐시된 검증 결과 확인
      const cacheKey = this.generateValidationCacheKey(formData, components, tableName);
      const cached = this.validationCache.get(cacheKey);
      if (cached) {
        console.log("📋 캐시된 검증 결과 사용");
        return cached;
      }

      // 테이블 컬럼 정보 조회 (캐시 사용)
      const tableColumns = await this.getTableColumns(tableName);

      // 폼 데이터 검증 수행
      const validationResult = await validateFormData(formData, components, tableColumns, tableName);

      // 결과 캐시 저장 (5분간)
      setTimeout(
        () => {
          this.validationCache.delete(cacheKey);
        },
        5 * 60 * 1000,
      );

      this.validationCache.set(cacheKey, validationResult);
      return validationResult;
    } catch (error) {
      console.error("❌ 클라이언트 검증 중 오류:", error);
      return {
        isValid: false,
        errors: [
          {
            field: "validation",
            code: "VALIDATION_ERROR",
            message: `검증 중 오류가 발생했습니다: ${error}`,
            severity: "error",
          },
        ],
        warnings: [],
      };
    }
  }

  /**
   * 테이블 컬럼 정보 조회 (캐시 포함)
   */
  private async getTableColumns(tableName: string): Promise<ColumnInfo[]> {
    // tableName이 비어있으면 빈 배열 반환
    if (!tableName || tableName.trim() === "") {
      console.warn("⚠️ getTableColumns: tableName이 비어있음");
      return [];
    }

    // 캐시 확인
    const cached = this.columnCache.get(tableName);
    if (cached) {
      return cached;
    }

    try {
      const response = await tableManagementApi.getColumnList(tableName);
      if (response.success && response.data) {
        const columns = response.data.map((col) => ({
          tableName: col.tableName || tableName,
          columnName: col.columnName,
          columnLabel: col.displayName,
          dataType: col.dataType,
          webType: col.webType,
          inputType: col.inputType,
          isNullable: col.isNullable,
          required: col.isNullable === "N",
          detailSettings: col.detailSettings,
          codeCategory: col.codeCategory,
          referenceTable: col.referenceTable,
          referenceColumn: col.referenceColumn,
          displayColumn: col.displayColumn,
          isVisible: col.isVisible,
          displayOrder: col.displayOrder,
          description: col.description,
        })) as ColumnInfo[];

        // 캐시 저장 (10분간)
        this.columnCache.set(tableName, columns);
        setTimeout(
          () => {
            this.columnCache.delete(tableName);
          },
          10 * 60 * 1000,
        );

        return columns;
      } else {
        throw new Error(response.message || "컬럼 정보 조회 실패");
      }
    } catch (error) {
      console.error("❌ 컬럼 정보 조회 실패:", error);
      throw error;
    }
  }

  /**
   * 폼 데이터 변환 및 정제
   */
  private async transformFormData(
    formData: Record<string, any>,
    components: ComponentData[],
    tableName: string,
  ): Promise<Record<string, any>> {
    const transformed = { ...formData };
    const tableColumns = await this.getTableColumns(tableName);
    const columnMap = new Map(tableColumns.map((col) => [col.columnName, col]));

    for (const [key, value] of Object.entries(transformed)) {
      const column = columnMap.get(key);
      if (!column) continue;

      // 빈 문자열을 null로 변환 (nullable 컬럼인 경우)
      if (value === "" && column.isNullable === "Y") {
        transformed[key] = null;
        continue;
      }

      // 데이터 타입별 변환
      if (value !== null && value !== undefined) {
        transformed[key] = this.convertValueByDataType(value, column.dataType);
      }
    }

    // 시스템 필드 자동 추가
    // created_date는 백엔드에서 처리하도록 프론트엔드에서 제거
    // (기존 데이터 조회 시 포함된 created_date가 그대로 전송되는 문제 방지)
    if (tableColumns.some((col) => col.columnName === "created_date")) {
      delete transformed.created_date;
    }
    if (!transformed.updated_date && tableColumns.some((col) => col.columnName === "updated_date")) {
      transformed.updated_date = now;
    }

    console.log("🔄 데이터 변환 완료:", {
      original: Object.keys(formData).length,
      transformed: Object.keys(transformed).length,
      changes: Object.keys(transformed).filter((key) => transformed[key] !== formData[key]),
    });

    return transformed;
  }

  /**
   * 데이터 타입별 값 변환
   */
  private convertValueByDataType(value: any, dataType: string): any {
    const lowerDataType = dataType.toLowerCase();

    // 숫자 타입
    if (lowerDataType.includes("integer") || lowerDataType.includes("bigint") || lowerDataType.includes("serial")) {
      const num = parseInt(value);
      return isNaN(num) ? null : num;
    }

    if (
      lowerDataType.includes("numeric") ||
      lowerDataType.includes("decimal") ||
      lowerDataType.includes("real") ||
      lowerDataType.includes("double")
    ) {
      const num = parseFloat(value);
      return isNaN(num) ? null : num;
    }

    // 불린 타입
    if (lowerDataType.includes("boolean")) {
      if (typeof value === "boolean") return value;
      if (typeof value === "string") {
        return value.toLowerCase() === "true" || value === "1" || value === "Y";
      }
      return Boolean(value);
    }

    // 날짜/시간 타입
    if (lowerDataType.includes("timestamp") || lowerDataType.includes("datetime")) {
      const date = new Date(value);
      return isNaN(date.getTime()) ? null : date.toISOString();
    }

    if (lowerDataType.includes("date")) {
      const date = new Date(value);
      return isNaN(date.getTime()) ? null : `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
    }

    if (lowerDataType.includes("time")) {
      // 시간 형식 변환 로직
      return value;
    }

    // JSON 타입
    if (lowerDataType.includes("json")) {
      if (typeof value === "string") {
        try {
          JSON.parse(value);
          return value;
        } catch {
          return JSON.stringify(value);
        }
      }
      return JSON.stringify(value);
    }

    // 기본값: 문자열
    return String(value);
  }

  /**
   * 서버 저장 수행
   */
  private async performServerSave(
    screenId: number,
    tableName: string,
    formData: Record<string, any>,
    options: SaveOptions,
  ): Promise<{ success: boolean; message?: string; data?: any }> {
    try {
      const result = await dynamicFormApi.saveData({
        screenId,
        tableName,
        data: formData,
      });

      return {
        success: result.success,
        message: result.message || "저장이 완료되었습니다.",
        data: result.data,
      };
    } catch (error: any) {
      console.error("❌ 서버 저장 오류:", error);

      // 에러 타입별 처리
      if (error.response?.status === 400) {
        return {
          success: false,
          message: "잘못된 요청: " + (error.response.data?.message || "데이터 형식을 확인해주세요."),
        };
      }

      if (error.response?.status === 500) {
        return {
          success: false,
          message: "서버 오류: " + (error.response.data?.message || "잠시 후 다시 시도해주세요."),
        };
      }

      return {
        success: false,
        message: error.message || "저장 중 알 수 없는 오류가 발생했습니다.",
      };
    }
  }

  /**
   * 검증 캐시 키 생성
   */
  private generateValidationCacheKey(
    formData: Record<string, any>,
    components: ComponentData[],
    tableName: string,
  ): string {
    const dataHash = JSON.stringify(formData);
    const componentsHash = JSON.stringify(
      components.map((c) => ({ id: c.id, type: c.type, columnName: (c as any).columnName })),
    );
    return `${tableName}:${btoa(dataHash + componentsHash).substring(0, 32)}`;
  }

  /**
   * 검증 메시지 포맷팅
   */
  private formatValidationMessage(validationResult: ValidationResult): string {
    const errorMessages = validationResult.errors.filter((e) => e.severity === "error").map((e) => e.message);

    if (errorMessages.length === 0) {
      return "알 수 없는 검증 오류가 발생했습니다.";
    }

    if (errorMessages.length === 1) {
      return errorMessages[0];
    }

    return `다음 오류들을 수정해주세요:\n• ${errorMessages.join("\n• ")}`;
  }

  /**
   * 캐시 클리어
   */
  public clearCache(): void {
    this.columnCache.clear();
    this.validationCache.clear();
    console.log("🧹 폼 서비스 캐시가 클리어되었습니다.");
  }

  /**
   * 테이블별 캐시 클리어
   */
  public clearTableCache(tableName: string): void {
    this.columnCache.delete(tableName);
    console.log(`🧹 테이블 '${tableName}' 캐시가 클리어되었습니다.`);
  }
}

// 싱글톤 인스턴스 내보내기
export const enhancedFormService = EnhancedFormService.getInstance();

// 편의 함수들
export const saveFormDataEnhanced = (context: SaveContext): Promise<EnhancedSaveResult> => {
  return enhancedFormService.saveFormData(context);
};

export const clearFormCache = (): void => {
  enhancedFormService.clearCache();
};

export const clearTableFormCache = (tableName: string): void => {
  enhancedFormService.clearTableCache(tableName);
};
