/**
 * 매핑 제약사항 검증 유틸리티
 * INSERT/UPDATE/DELETE 액션의 매핑 규칙을 검증합니다.
 */

export interface ValidationResult {
  isValid: boolean;
  error?: string;
  warnings?: string[];
}

export interface ColumnMapping {
  id?: string;
  fromColumnName?: string;
  toColumnName: string;
  sourceTable?: string;
  targetTable?: string;
  defaultValue?: string;
  transformFunction?: string;
}

export interface UpdateCondition {
  id: string;
  fromColumn: string;
  operator: string;
  value: string | string[];
  logicalOperator?: "AND" | "OR";
}

export interface WhereCondition {
  id: string;
  toColumn: string;
  operator: string;
  valueSource: string;
  fromColumn?: string;
  staticValue?: string;
  logicalOperator?: "AND" | "OR";
}

export interface DeleteCondition {
  id: string;
  fromColumn: string;
  operator: string;
  value: string | string[];
  logicalOperator?: "AND" | "OR";
}

/**
 * 전체 매핑 제약사항 검증
 */
export const validateMappingConstraints = (
  actionType: "insert" | "update" | "delete",
  newMapping: ColumnMapping,
  existingMappings: ColumnMapping[],
): ValidationResult => {
  switch (actionType) {
    case "insert":
      return validateInsertMapping(newMapping, existingMappings);
    case "update":
      return validateUpdateMapping(newMapping, existingMappings);
    case "delete":
      return validateDeleteConditions(newMapping, existingMappings);
    default:
      return { isValid: false, error: "지원하지 않는 액션 타입입니다." };
  }
};

/**
 * INSERT 매핑 검증
 * 규칙: 1:N 매핑 허용, N:1 매핑 금지
 */
export const validateInsertMapping = (
  newMapping: ColumnMapping,
  existingMappings: ColumnMapping[],
): ValidationResult => {
  // TO 컬럼이 이미 다른 FROM 컬럼과 매핑되어 있는지 확인
  const existingToMapping = existingMappings.find((mapping) => mapping.toColumnName === newMapping.toColumnName);

  if (
    existingToMapping &&
    existingToMapping.fromColumnName &&
    existingToMapping.fromColumnName !== newMapping.fromColumnName
  ) {
    return {
      isValid: false,
      error: `대상 컬럼 '${newMapping.toColumnName}'은 이미 '${existingToMapping.fromColumnName}'과 매핑되어 있습니다.`,
    };
  }

  // 기본값이 설정된 경우와 FROM 컬럼이 동시에 설정되어 있는지 확인
  if (newMapping.fromColumnName && newMapping.defaultValue && newMapping.defaultValue.trim()) {
    return {
      isValid: false,
      error: `'${newMapping.toColumnName}' 컬럼에는 FROM 컬럼과 기본값을 동시에 설정할 수 없습니다.`,
    };
  }

  return { isValid: true };
};

/**
 * UPDATE 매핑 검증
 */
export const validateUpdateMapping = (
  newMapping: ColumnMapping,
  existingMappings: ColumnMapping[],
): ValidationResult => {
  // 기본 INSERT 규칙 적용
  const baseValidation = validateInsertMapping(newMapping, existingMappings);
  if (!baseValidation.isValid) {
    return baseValidation;
  }

  // UPDATE 특화 검증 로직 추가 가능
  return { isValid: true };
};

/**
 * DELETE 조건 검증
 */
export const validateDeleteConditions = (
  newMapping: ColumnMapping,
  existingMappings: ColumnMapping[],
): ValidationResult => {
  // DELETE는 기본적으로 조건 기반이므로 매핑 제약이 다름
  return { isValid: true };
};

/**
 * 자기 자신 테이블 UPDATE 작업 검증
 */
export const validateSelfTableUpdate = (
  fromTable: string,
  toTable: string,
  updateConditions: UpdateCondition[],
  whereConditions: WhereCondition[],
): ValidationResult => {
  if (fromTable === toTable) {
    // 1. WHERE 조건 필수
    if (!whereConditions.length) {
      return {
        isValid: false,
        error: "자기 자신 테이블 업데이트 시 WHERE 조건이 필수입니다.",
      };
    }

    // 2. 업데이트 조건과 WHERE 조건이 겹치지 않도록 체크
    const conditionColumns = updateConditions.map((c) => c.fromColumn);
    const whereColumns = whereConditions.map((c) => c.toColumn);
    const overlap = conditionColumns.filter((col) => whereColumns.includes(col));

    if (overlap.length > 0) {
      return {
        isValid: false,
        error: `업데이트 조건과 WHERE 조건에서 같은 컬럼(${overlap.join(", ")})을 사용하면 예상치 못한 결과가 발생할 수 있습니다.`,
      };
    }

    // 3. 무한 루프 방지 체크
    const hasInfiniteLoopRisk = updateConditions.some((condition) =>
      whereConditions.some(
        (where) => where.fromColumn === condition.toColumn && where.toColumn === condition.fromColumn,
      ),
    );

    if (hasInfiniteLoopRisk) {
      return {
        isValid: false,
        error: "자기 참조 업데이트로 인한 무한 루프 위험이 있습니다.",
      };
    }
  }

  return { isValid: true };
};

/**
 * 자기 자신 테이블 DELETE 작업 검증
 */
export const validateSelfTableDelete = (
  fromTable: string,
  toTable: string,
  deleteConditions: DeleteCondition[],
  whereConditions: WhereCondition[],
  maxDeleteCount: number,
): ValidationResult => {
  if (fromTable === toTable) {
    // 1. WHERE 조건 필수 체크
    if (!whereConditions.length) {
      return {
        isValid: false,
        error: "자기 자신 테이블 삭제 시 WHERE 조건이 필수입니다.",
      };
    }

    // 2. 강화된 안전장치: 더 엄격한 제한
    const selfDeleteMaxCount = Math.min(maxDeleteCount, 10);

    if (maxDeleteCount > selfDeleteMaxCount) {
      return {
        isValid: false,
        error: `자기 자신 테이블 삭제 시 최대 ${selfDeleteMaxCount}개까지만 허용됩니다.`,
      };
    }

    // 3. 삭제 조건이 너무 광범위한지 체크
    const hasBroadCondition = deleteConditions.some(
      (condition) =>
        condition.operator === "!=" || condition.operator === "NOT IN" || condition.operator === "NOT EXISTS",
    );

    if (hasBroadCondition) {
      return {
        isValid: false,
        error: "자기 자신 테이블 삭제 시 부정 조건(!=, NOT IN, NOT EXISTS)은 위험합니다.",
      };
    }

    // 4. WHERE 조건이 충분히 구체적인지 체크
    if (whereConditions.length < 2) {
      return {
        isValid: false,
        error: "자기 자신 테이블 삭제 시 WHERE 조건을 2개 이상 설정하는 것을 권장합니다.",
        warnings: ["안전을 위해 더 구체적인 조건을 설정하세요."],
      };
    }
  }

  return { isValid: true };
};

/**
 * 컬럼 데이터 타입 호환성 검증
 */
export const validateDataTypeCompatibility = (fromColumnType: string, toColumnType: string): ValidationResult => {
  // 기본 호환성 규칙
  const fromType = normalizeDataType(fromColumnType);
  const toType = normalizeDataType(toColumnType);

  // 같은 타입이면 호환
  if (fromType === toType) {
    return { isValid: true };
  }

  // 숫자 타입 간 호환성
  const numericTypes = ["int", "integer", "bigint", "smallint", "decimal", "numeric", "float", "double"];
  if (numericTypes.includes(fromType) && numericTypes.includes(toType)) {
    return {
      isValid: true,
      warnings: ["숫자 타입 간 변환 시 정밀도 손실이 발생할 수 있습니다."],
    };
  }

  // 문자열 타입 간 호환성
  const stringTypes = ["varchar", "char", "text", "string"];
  if (stringTypes.includes(fromType) && stringTypes.includes(toType)) {
    return {
      isValid: true,
      warnings: ["문자열 길이 제한을 확인하세요."],
    };
  }

  // 날짜/시간 타입 간 호환성
  const dateTypes = ["date", "datetime", "timestamp", "time"];
  if (dateTypes.includes(fromType) && dateTypes.includes(toType)) {
    return {
      isValid: true,
      warnings: ["날짜/시간 형식 변환 시 데이터 손실이 발생할 수 있습니다."],
    };
  }

  // 호환되지 않는 타입
  return {
    isValid: false,
    error: `'${fromColumnType}' 타입과 '${toColumnType}' 타입은 호환되지 않습니다.`,
  };
};

/**
 * 데이터 타입 정규화
 */
const normalizeDataType = (dataType: string): string => {
  const lowerType = dataType.toLowerCase();

  // 정수 타입
  if (lowerType.includes("int") || lowerType.includes("serial")) {
    return "int";
  }

  // 실수 타입
  if (
    lowerType.includes("decimal") ||
    lowerType.includes("numeric") ||
    lowerType.includes("float") ||
    lowerType.includes("double")
  ) {
    return "decimal";
  }

  // 문자열 타입
  if (
    lowerType.includes("varchar") ||
    lowerType.includes("char") ||
    lowerType.includes("text") ||
    lowerType.includes("string")
  ) {
    return "varchar";
  }

  // 날짜 타입
  if (lowerType.includes("date")) {
    return "date";
  }

  // 시간 타입
  if (lowerType.includes("time")) {
    return "datetime";
  }

  // 불린 타입
  if (lowerType.includes("bool")) {
    return "boolean";
  }

  return lowerType;
};

/**
 * 매핑 완성도 검증
 */
export const validateMappingCompleteness = (requiredColumns: string[], mappings: ColumnMapping[]): ValidationResult => {
  const mappedColumns = mappings.map((m) => m.toColumnName);
  const unmappedRequired = requiredColumns.filter((col) => !mappedColumns.includes(col));

  if (unmappedRequired.length > 0) {
    return {
      isValid: false,
      error: `필수 컬럼이 매핑되지 않았습니다: ${unmappedRequired.join(", ")}`,
    };
  }

  return { isValid: true };
};

/**
 * 전체 액션 설정 검증
 */
export const validateActionConfiguration = (
  actionType: "insert" | "update" | "delete",
  fromTable?: string,
  toTable?: string,
  mappings?: ColumnMapping[],
  conditions?: any[],
): ValidationResult => {
  // 기본 필수 정보 체크
  if (!toTable) {
    return {
      isValid: false,
      error: "대상 테이블을 선택해야 합니다.",
    };
  }

  // 액션 타입별 검증
  switch (actionType) {
    case "insert":
      if (!mappings || mappings.length === 0) {
        return {
          isValid: false,
          error: "INSERT 작업에는 최소 하나의 필드 매핑이 필요합니다.",
        };
      }
      break;

    case "update":
      if (!fromTable) {
        return {
          isValid: false,
          error: "UPDATE 작업에는 조건 확인용 소스 테이블이 필요합니다.",
        };
      }
      if (!conditions || conditions.length === 0) {
        return {
          isValid: false,
          error: "UPDATE 작업에는 WHERE 조건이 필요합니다.",
        };
      }
      break;

    case "delete":
      if (!fromTable) {
        return {
          isValid: false,
          error: "DELETE 작업에는 조건 확인용 소스 테이블이 필요합니다.",
        };
      }
      if (!conditions || conditions.length === 0) {
        return {
          isValid: false,
          error: "DELETE 작업에는 WHERE 조건이 필요합니다.",
        };
      }
      break;
  }

  return { isValid: true };
};
