import axios from 'axios';
import { getApiBaseUrl } from './apiConfig';

// ============================================================
// 타입 정의
// ============================================================

/**
 * LogicNode 타입
 */
export type LogicNodeType = 'AND' | 'OR' | 'NOT' | 'CONDITION';

/**
 * ConditionDSL 인터페이스
 */
export interface ConditionDSL {
  indicatorType: string;
  conditionType: string;
  targetValue?: number;
  secondaryValue?: number;
  period?: number;
  comparePeriod?: number;
  params?: Record<string, any>;
  
  // ==================== 일목균형표 전용 필드 ====================
  
  /**
   * 왼쪽 필드 (일목균형표 조건용)
   * 예: 'CONVERSION_LINE', 'BASE_LINE', 'LEADING_SPAN1', 'CLOSE_PRICE' 등
   */
  leftField?: string;
  
  /**
   * 오른쪽 필드 (일목균형표 조건용)
   * 예: 'BASE_LINE', 'LEADING_SPAN2' 등
   */
  rightField?: string;
  
  /**
   * 비교값 (일목균형표 DIFF_GT, DIFF_LT 조건용)
   */
  compareValue?: number;
  
  /**
   * 기울기 기간 (일목균형표 SLOPE_UP, SLOPE_DOWN 조건용)
   * N일 전과 비교
   */
  slopePeriod?: number;
  
  /**
   * 유지 일수 (일목균형표 HOLD_N_DAYS 조건용)
   * 조건이 N일 연속 만족해야 함
   */
  holdDays?: number;
  
  /**
   * 조건 체크 캔들 범위
   * 1 = 현재 캔들만
   * 2 = 현재 + 이전 1개 캔들
   * 3 = 현재 + 이전 2개 캔들
   * 기본값: 1
   */
  candleRange?: number;
}

/**
 * LogicNode 인터페이스 (재귀 구조)
 */
export interface LogicNode {
  id: string;
  type: LogicNodeType;
  children?: LogicNode[];
  condition?: ConditionDSL;
  description?: string;
  metadata?: string;
}

/**
 * Strategy Stats
 */
export interface StrategyStats {
  totalNodes: number;
  conditionCount: number;
  maxDepth: number;
  indicators: string[];
  complexityScore: number;
}

/**
 * StrategyDSL DTO
 */
export interface StrategyDSLDto {
  id?: number;
  name: string;
  description?: string;
  dslJson: string; // JSON.stringify(LogicNode)
  strategyType?: string;
  createdByUi?: string;
  enabled?: boolean;
  useFsm?: boolean;
  createdBy?: string;
  createdAt?: string;
  updatedAt?: string;
  migratedAt?: string;
  stats?: StrategyStats;
}

/**
 * StrategyDSL 생성 요청
 */
export interface CreateStrategyDSLRequest {
  name: string;
  description?: string;
  dslJson: string;
  enabled?: boolean;
  useFsm?: boolean;
}

/**
 * StrategyDSL 수정 요청
 */
export interface UpdateStrategyDSLRequest {
  name: string;
  description?: string;
  dslJson: string;
  enabled?: boolean;
  useFsm?: boolean;
}

// ============================================================
// API 기본 설정
// ============================================================

// API 베이스 URL (apiConfig에서 가져오기)
const API_BASE_URL = getApiBaseUrl().replace('/api', ''); // /api 제거 (이 파일에서는 경로에 직접 포함)

// Axios 인스턴스 생성
const apiClient = axios.create({
  baseURL: API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

// ============================================================
// API 함수들
// ============================================================

/**
 * DSL 전략 목록 조회
 */
export const getDSLStrategies = async (activeOnly: boolean = false): Promise<StrategyDSLDto[]> => {
  try {
    const response = await apiClient.get<StrategyDSLDto[]>(
      `/api/strategies/dsl`,
      {
        params: { activeOnly },
      }
    );
    return response.data;
  } catch (error) {
    console.error('❌ DSL 전략 목록 조회 실패:', error);
    throw error;
  }
};

/**
 * DSL 전략 조회 (단건)
 */
export const getDSLStrategy = async (id: number): Promise<StrategyDSLDto> => {
  try {
    const response = await apiClient.get<StrategyDSLDto>(
      `/api/strategies/dsl/${id}`
    );
    return response.data;
  } catch (error) {
    console.error(`❌ DSL 전략 조회 실패 (ID: ${id}):`, error);
    throw error;
  }
};

/**
 * DSL 전략 생성
 */
export const createDSLStrategy = async (
  request: CreateStrategyDSLRequest
): Promise<StrategyDSLDto> => {
  try {
    console.log('🎨 DSL 전략 생성 요청:', request);
    
    const dto: StrategyDSLDto = {
      name: request.name,
      description: request.description,
      dslJson: request.dslJson,
      strategyType: 'DSL',
      createdByUi: 'TREE',
      enabled: request.enabled !== undefined ? request.enabled : true,
      useFsm: request.useFsm !== undefined ? request.useFsm : false,
    };
    
    const response = await apiClient.post<StrategyDSLDto>(
      `/api/strategies/dsl`,
      dto
    );
    
    console.log('✅ DSL 전략 생성 성공:', response.data);
    return response.data;
  } catch (error: any) {
    console.error('❌ DSL 전략 생성 실패:', error);
    if (error?.response) {
      console.error('  → status:', error.response.status);
      console.error('  → url:', error.config?.baseURL, error.config?.url);
      console.error('  → response:', error.response.data);
    } else if (error?.code === 'ERR_NETWORK' || error?.message?.includes('Network')) {
      console.error('  → 네트워크 오류: 백엔드(8083) 실행 여부 확인');
    }
    throw error;
  }
};

/**
 * DSL 전략 수정
 */
export const updateDSLStrategy = async (
  id: number,
  request: UpdateStrategyDSLRequest
): Promise<StrategyDSLDto> => {
  try {
    console.log(`✏️ DSL 전략 수정 요청 (ID: ${id}):`, request);
    
    const dto: StrategyDSLDto = {
      id,
      name: request.name,
      description: request.description,
      dslJson: request.dslJson,
      strategyType: 'DSL',
      createdByUi: 'TREE',
      enabled: request.enabled,
      useFsm: request.useFsm,
    };
    
    const response = await apiClient.put<StrategyDSLDto>(
      `/api/strategies/dsl/${id}`,
      dto
    );
    
    console.log('✅ DSL 전략 수정 성공:', response.data);
    return response.data;
  } catch (error) {
    console.error(`❌ DSL 전략 수정 실패 (ID: ${id}):`, error);
    throw error;
  }
};

/**
 * DSL 전략 삭제
 */
export const deleteDSLStrategy = async (id: number): Promise<void> => {
  try {
    console.log(`🗑️ DSL 전략 삭제 요청 (ID: ${id})`);
    
    await apiClient.delete(`/api/strategies/dsl/${id}`);
    
    console.log(`✅ DSL 전략 삭제 성공 (ID: ${id})`);
  } catch (error) {
    console.error(`❌ DSL 전략 삭제 실패 (ID: ${id}):`, error);
    throw error;
  }
};

/**
 * DSL 전략 활성화/비활성화 토글
 */
export const toggleDSLStrategy = async (id: number): Promise<{ id: number; enabled: boolean }> => {
  try {
    const response = await apiClient.patch<{ id: number; enabled: boolean }>(
      `/api/strategies/dsl/${id}/toggle`
    );
    return response.data;
  } catch (error) {
    console.error(`❌ DSL 전략 토글 실패 (ID: ${id}):`, error);
    throw error;
  }
};

/**
 * FSM 사용 토글
 */
export const toggleDSLStrategyFSM = async (id: number): Promise<{ id: number; useFsm: boolean }> => {
  try {
    const response = await apiClient.patch<{ id: number; useFsm: boolean }>(
      `/api/strategies/dsl/${id}/toggle-fsm`
    );
    return response.data;
  } catch (error) {
    console.error(`❌ FSM 토글 실패 (ID: ${id}):`, error);
    throw error;
  }
};

/**
 * DSL 전략 복제
 */
export const duplicateDSLStrategy = async (
  id: number,
  newName: string
): Promise<StrategyDSLDto> => {
  try {
    console.log(`📋 DSL 전략 복제 요청 (ID: ${id}, 새 이름: ${newName})`);
    
    const response = await apiClient.post<StrategyDSLDto>(
      `/api/strategies/dsl/${id}/duplicate`,
      { name: newName }
    );
    
    console.log('✅ DSL 전략 복제 성공:', response.data);
    return response.data;
  } catch (error) {
    console.error(`❌ DSL 전략 복제 실패 (ID: ${id}):`, error);
    throw error;
  }
};

/**
 * DSL 전략 검색
 */
export const searchDSLStrategies = async (keyword: string): Promise<StrategyDSLDto[]> => {
  try {
    const response = await apiClient.get<StrategyDSLDto[]>(
      `/api/strategies/dsl/search`,
      {
        params: { keyword },
      }
    );
    return response.data;
  } catch (error) {
    console.error(`❌ DSL 전략 검색 실패 (keyword: ${keyword}):`, error);
    throw error;
  }
};

/**
 * Legacy 전략을 DSL로 마이그레이션
 */
export const migrateLegacyToDSL = async (legacyId: number): Promise<StrategyDSLDto> => {
  try {
    console.log(`🔄 Legacy → DSL 마이그레이션 요청 (ID: ${legacyId})`);
    
    const response = await apiClient.post<StrategyDSLDto>(
      `/api/strategies/dsl/migrate/${legacyId}`
    );
    
    console.log('✅ 마이그레이션 성공:', response.data);
    return response.data;
  } catch (error) {
    console.error(`❌ 마이그레이션 실패 (ID: ${legacyId}):`, error);
    throw error;
  }
};

/**
 * DSL 유효성 검증
 */
export const validateDSL = async (dslJson: string): Promise<{ valid: boolean; message: string }> => {
  try {
    const response = await apiClient.post<{ valid: boolean; message: string }>(
      `/api/strategies/dsl/validate`,
      {
        name: 'temp',
        dslJson,
        strategyType: 'DSL',
        createdByUi: 'TREE',
      }
    );
    return response.data;
  } catch (error) {
    console.error('❌ DSL 유효성 검증 실패:', error);
    throw error;
  }
};

/**
 * 헬스 체크
 */
export const checkDSLHealth = async (): Promise<any> => {
  try {
    const response = await apiClient.get(`/api/strategies/dsl/health`);
    return response.data;
  } catch (error) {
    console.error('❌ 헬스 체크 실패:', error);
    throw error;
  }
};

// ============================================================
// 유틸리티 함수들
// ============================================================

/**
 * 빈 LogicNode 생성
 */
export const createEmptyLogicNode = (type: LogicNodeType): LogicNode => {
  return {
    id: generateNodeId(),
    type,
    children: type !== 'CONDITION' ? [] : undefined,
    condition: type === 'CONDITION' ? createEmptyCondition() : undefined,
    description: '',
  };
};

/**
 * 빈 Condition 생성
 */
export const createEmptyCondition = (): ConditionDSL => {
  return {
    indicatorType: 'CCI',
    conditionType: 'CROSS_UP',
    targetValue: -100,
    period: 20,
    candleRange: 1,
  };
};

/**
 * 노드 ID 생성 (UUID v4 간단 버전)
 */
export const generateNodeId = (): string => {
  return `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
};

/**
 * LogicNode 유효성 검증
 */
export const validateLogicNode = (node: LogicNode): boolean => {
  if (!node.id || !node.type) {
    return false;
  }
  
  if (node.type === 'CONDITION') {
    return node.condition !== undefined && validateCondition(node.condition);
  }
  
  if (node.type === 'NOT') {
    return node.children !== undefined && node.children.length === 1;
  }
  
  if (node.type === 'AND' || node.type === 'OR') {
    return node.children !== undefined && node.children.length > 0;
  }
  
  return false;
};

/**
 * Condition 유효성 검증
 */
export const validateCondition = (condition: ConditionDSL): boolean => {
  if (!condition.indicatorType || !condition.conditionType) {
    return false;
  }
  
  // 일목균형표 조건 검증
  if (condition.indicatorType === 'ICHIMOKU') {
    return validateIchimokuCondition(condition);
  }
  
  // 볼린저밴드 조건 검증
  if (condition.indicatorType === 'BOLLINGER') {
    return validateBollingerCondition(condition);
  }
  
  // MACD 조건 검증
  if (condition.indicatorType === 'MACD') {
    return validateMacdCondition(condition);
  }
  
  // RSI 조건 검증
  if (condition.indicatorType === 'RSI') {
    return validateRsiCondition(condition);
  }
  
  // Stochastic 조건 검증
  if (condition.indicatorType === 'STOCHASTIC') {
    return validateBollingerCondition(condition);
  }
  
  // CCI 조건 검증
  if (condition.indicatorType === 'CCI') {
    return validateBollingerCondition(condition);
  }
  
  // ADX 조건 검증
  if (condition.indicatorType === 'ADX') {
    return validateBollingerCondition(condition);
  }
  
  // TRIX 조건 검증
  if (condition.indicatorType === 'TRIX') {
    return validateBollingerCondition(condition);
  }
  
  // DMI 조건 검증
  if (condition.indicatorType === 'DMI') {
    return validateBollingerCondition(condition);
  }
  
  // OBV 조건 검증
  if (condition.indicatorType === 'OBV') {
    return validateBollingerCondition(condition);
  }
  
  // VOLUME 조건 검증
  if (condition.indicatorType === 'VOLUME') {
    return validateBollingerCondition(condition);
  }
  
  // MA 조건 검증
  if (condition.indicatorType === 'MA') {
    return validateBollingerCondition(condition);
  }
  
  // DISPARITY 조건 검증
  if (condition.indicatorType === 'DISPARITY') {
    return validateBollingerCondition(condition);
  }
  
  // NEW_PSYCHOLOGICAL 조건 검증
  if (condition.indicatorType === 'NEW_PSYCHOLOGICAL') {
    return validateBollingerCondition(condition);
  }
  
  // INVEST_PSYCHOLOGICAL 조건 검증
  if (condition.indicatorType === 'INVEST_PSYCHOLOGICAL') {
    return validateBollingerCondition(condition);
  }
  
  // WILLIAMS_R 조건 검증
  if (condition.indicatorType === 'WILLIAMS_R') {
    return validateBollingerCondition(condition);
  }
  
  // BWI 조건 검증
  if (condition.indicatorType === 'BWI') {
    return validateBollingerCondition(condition);
  }
  
  // VR 조건 검증
  if (condition.indicatorType === 'VR') {
    return validateBollingerCondition(condition);
  }
  
  // VOLUME_OSC 조건 검증
  if (condition.indicatorType === 'VOLUME_OSC') {
    return validateBollingerCondition(condition);
  }
  
  // GOLDEN_CROSS, DEAD_CROSS는 targetValue 불필요
  if (condition.conditionType === 'GOLDEN_CROSS' || 
      condition.conditionType === 'DEAD_CROSS') {
    return true;
  }
  
  // BETWEEN 조건은 targetValue와 secondaryValue 모두 필요
  if (condition.conditionType === 'BETWEEN') {
    return condition.targetValue !== undefined && 
           condition.secondaryValue !== undefined;
  }
  
  // 대부분의 조건은 targetValue 필요
  return condition.targetValue !== undefined;
};

/**
 * 일목균형표 조건 유효성 검증
 */
export const validateIchimokuCondition = (condition: ConditionDSL): boolean => {
  const { conditionType } = condition;
  
  // 기본 비교형 (GT, LT, GTE, LTE, EQ, NEQ)
  if (['GT', 'LT', 'GTE', 'LTE', 'EQ', 'NEQ'].includes(conditionType)) {
    return !!condition.leftField && !!condition.rightField;
  }
  
  // 교차형 (CROSS_UP, CROSS_DOWN)
  if (['CROSS_UP', 'CROSS_DOWN'].includes(conditionType)) {
    return !!condition.leftField && !!condition.rightField;
  }
  
  // 구름 위치형 (ABOVE_CLOUD, BELOW_CLOUD, IN_CLOUD, CLOUD_BREAK_UP, CLOUD_BREAK_DOWN)
  if (['ABOVE_CLOUD', 'BELOW_CLOUD', 'IN_CLOUD', 'CLOUD_BREAK_UP', 'CLOUD_BREAK_DOWN'].includes(conditionType)) {
    return true; // 추가 필드 불필요
  }
  
  // 구름 전환 (SPAN1_GT_SPAN2, SPAN1_LT_SPAN2, SPAN1_CROSS_UP_SPAN2, SPAN1_CROSS_DOWN_SPAN2)
  if (['SPAN1_GT_SPAN2', 'SPAN1_LT_SPAN2', 'SPAN1_CROSS_UP_SPAN2', 'SPAN1_CROSS_DOWN_SPAN2'].includes(conditionType)) {
    return true; // 추가 필드 불필요
  }
  
  // 후행스팬 위치 (LAGGING_GT_PRICE, LAGGING_LT_PRICE)
  if (['LAGGING_GT_PRICE', 'LAGGING_LT_PRICE'].includes(conditionType)) {
    return true; // 추가 필드 불필요
  }
  
  // 기울기형 (SLOPE_UP, SLOPE_DOWN)
  if (['SLOPE_UP', 'SLOPE_DOWN'].includes(conditionType)) {
    return !!condition.leftField && 
           condition.slopePeriod !== undefined && 
           condition.slopePeriod > 0 && 
           condition.slopePeriod <= 100;
  }
  
  // 차이형 (DIFF_GT, DIFF_LT)
  if (['DIFF_GT', 'DIFF_LT'].includes(conditionType)) {
    return !!condition.leftField && 
           !!condition.rightField && 
           condition.compareValue !== undefined;
  }
  
  // 유지형 (HOLD_N_DAYS)
  if (conditionType === 'HOLD_N_DAYS') {
    return condition.holdDays !== undefined && 
           condition.holdDays > 0 && 
           condition.holdDays <= 30;
  }
  
  return true;
};

/**
 * 볼린저밴드 조건 유효성 검증
 */
export const validateBollingerCondition = (condition: ConditionDSL): boolean => {
  const { conditionType } = condition;
  
  // 기본 비교형 (GT, LT, GTE, LTE, EQ, NEQ)
  if (['GT', 'LT', 'GTE', 'LTE', 'EQ', 'NEQ'].includes(conditionType)) {
    return !!condition.leftField && !!condition.rightField;
  }
  
  // 교차형 (CROSS_UP, CROSS_DOWN)
  if (['CROSS_UP', 'CROSS_DOWN'].includes(conditionType)) {
    return !!condition.leftField && !!condition.rightField;
  }
  
  // 기울기형 (SLOPE_UP, SLOPE_DOWN)
  if (['SLOPE_UP', 'SLOPE_DOWN'].includes(conditionType)) {
    return !!condition.leftField && 
           condition.slopePeriod !== undefined && 
           condition.slopePeriod > 0 && 
           condition.slopePeriod <= 100;
  }
  
  // 차이형 (DIFF_GT, DIFF_LT)
  if (['DIFF_GT', 'DIFF_LT'].includes(conditionType)) {
    return !!condition.leftField && 
           !!condition.rightField && 
           condition.compareValue !== undefined;
  }
  
  // 유지형 (HOLD_N_DAYS)
  if (conditionType === 'HOLD_N_DAYS') {
    return condition.holdDays !== undefined && 
           condition.holdDays > 0 && 
           condition.holdDays <= 30;
  }
  
  return true;
};

/**
 * MACD 조건 유효성 검증
 */
export const validateMacdCondition = (condition: ConditionDSL): boolean => {
  return validateBollingerCondition(condition);
};

/**
 * RSI 조건 유효성 검증
 */
export const validateRsiCondition = (condition: ConditionDSL): boolean => {
  return validateBollingerCondition(condition);
};

/**
 * Stochastic 조건을 자연어로 변환
 */
const formatStochasticCondition = (condition: ConditionDSL): string => {
  const leftField = getStochasticFieldLabel(condition.leftField);
  const rightField = getStochasticFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `Stochastic - ${condition.conditionType}`;
  }
};

const getStochasticFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'STOCH_K': 'Stochastic %K', 'STOCH_D': 'Stochastic %D',
    'OVERBOUGHT_80': '과매수선(80)', 'NEUTRAL_50': '중립선(50)', 'OVERSOLD_20': '과매도선(20)',
  };
  return labels[field] || field;
};

const formatCciCondition = (condition: ConditionDSL): string => {
  const leftField = getCciFieldLabel(condition.leftField);
  const rightField = getCciFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `CCI - ${condition.conditionType}`;
  }
};

const getCciFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'CCI_VALUE': 'CCI 값',
    'OVERBOUGHT_100': '과매수선(100)', 'NEUTRAL_0': '중립선(0)', 'OVERSOLD_NEG100': '과매도선(-100)',
  };
  return labels[field] || field;
};

const formatAdxCondition = (condition: ConditionDSL): string => {
  const leftField = getAdxFieldLabel(condition.leftField);
  const rightField = getAdxFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `ADX - ${condition.conditionType}`;
  }
};

const getAdxFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'ADX_VALUE': 'ADX 값', 'ADX_25': '기준선(25)', 'ADX_50': '강한추세선(50)',
  };
  return labels[field] || field;
};

const formatTrixCondition = (condition: ConditionDSL): string => {
  const leftField = getTrixFieldLabel(condition.leftField);
  const rightField = getTrixFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `TRIX - ${condition.conditionType}`;
  }
};

const getTrixFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'TRIX_VALUE': 'TRIX 값', 'TRIX_SIGNAL': 'TRIX 시그널', 'ZERO_LINE': '0선',
  };
  return labels[field] || field;
};

const formatDmiCondition = (condition: ConditionDSL): string => {
  const leftField = getDmiFieldLabel(condition.leftField);
  const rightField = getDmiFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `DMI - ${condition.conditionType}`;
  }
};

const getDmiFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'PDI': '+DI', 'MDI': '-DI', 'ADX': 'ADX',
  };
  return labels[field] || field;
};

const formatObvCondition = (condition: ConditionDSL): string => {
  const leftField = getObvFieldLabel(condition.leftField);
  const rightField = getObvFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `OBV - ${condition.conditionType}`;
  }
};

const getObvFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'OBV_VALUE': 'OBV 값', 'ZERO_LINE': '0선',
  };
  return labels[field] || field;
};

const formatVolumeCondition = (condition: ConditionDSL): string => {
  const leftField = getVolumeFieldLabel(condition.leftField);
  const rightField = getVolumeFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `VOLUME - ${condition.conditionType}`;
  }
};

const getVolumeFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'VOLUME_VALUE': '거래량', 'VOLUME_MA': '거래량 이동평균',
  };
  return labels[field] || field;
};

const formatMaCondition = (condition: ConditionDSL): string => {
  const leftField = getMaFieldLabel(condition.leftField);
  const rightField = getMaFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `MA - ${condition.conditionType}`;
  }
};

const getMaFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'MA5': '5일 이동평균', 'MA10': '10일 이동평균', 'MA20': '20일 이동평균',
    'MA60': '60일 이동평균', 'MA120': '120일 이동평균', 'MA200': '200일 이동평균',
    'CLOSE_PRICE': '종가',
  };
  return labels[field] || field;
};

const formatDisparityCondition = (condition: ConditionDSL): string => {
  const leftField = getDisparityFieldLabel(condition.leftField);
  const rightField = getDisparityFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `DISPARITY - ${condition.conditionType}`;
  }
};

const getDisparityFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'DISPARITY5': '5일 이격도', 'DISPARITY10': '10일 이격도', 'DISPARITY20': '20일 이격도',
    'ZERO_LINE': '0선',
  };
  return labels[field] || field;
};

const formatNewPsychologicalCondition = (condition: ConditionDSL): string => {
  const leftField = getNewPsychologicalFieldLabel(condition.leftField);
  const rightField = getNewPsychologicalFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `신심리도 - ${condition.conditionType}`;
  }
};

const getNewPsychologicalFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'NEW_PSY_VALUE': '신심리도 값',
    'OVERBOUGHT_75': '과매수선(75)', 'NEUTRAL_50': '중립선(50)', 'OVERSOLD_25': '과매도선(25)',
  };
  return labels[field] || field;
};

const formatInvestPsychologicalCondition = (condition: ConditionDSL): string => {
  const leftField = getInvestPsychologicalFieldLabel(condition.leftField);
  const rightField = getInvestPsychologicalFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `투자심리도 - ${condition.conditionType}`;
  }
};

const getInvestPsychologicalFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'INVEST_PSY_VALUE': '투자심리도 값',
    'OVERBOUGHT_75': '과매수선(75)', 'NEUTRAL_50': '중립선(50)', 'OVERSOLD_25': '과매도선(25)',
  };
  return labels[field] || field;
};

const formatWilliamsRCondition = (condition: ConditionDSL): string => {
  const leftField = getWilliamsRFieldLabel(condition.leftField);
  const rightField = getWilliamsRFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `Williams %R - ${condition.conditionType}`;
  }
};

const getWilliamsRFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'WILLIAMS_R_VALUE': 'Williams %R 값',
    'OVERBOUGHT_NEG20': '과매수선(-20)', 'NEUTRAL_NEG50': '중립선(-50)', 'OVERSOLD_NEG80': '과매도선(-80)',
  };
  return labels[field] || field;
};

const formatBwiCondition = (condition: ConditionDSL): string => {
  const leftField = getBwiFieldLabel(condition.leftField);
  const rightField = getBwiFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `BWI - ${condition.conditionType}`;
  }
};

const getBwiFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'BWI_VALUE': 'BWI 값',
    'OVERBOUGHT_80': '과매수선(80)', 'NEUTRAL_50': '중립선(50)', 'OVERSOLD_20': '과매도선(20)',
  };
  return labels[field] || field;
};

const formatVrCondition = (condition: ConditionDSL): string => {
  const leftField = getVrFieldLabel(condition.leftField);
  const rightField = getVrFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `VR - ${condition.conditionType}`;
  }
};

const getVrFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'VR_VALUE': 'VR 값',
    'OVERBOUGHT_200': '과매수선(200)', 'NEUTRAL_100': '중립선(100)', 'OVERSOLD_50': '과매도선(50)',
  };
  return labels[field] || field;
};

const formatVolumeOscCondition = (condition: ConditionDSL): string => {
  const leftField = getVolumeOscFieldLabel(condition.leftField);
  const rightField = getVolumeOscFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `거래량 오실레이터 - ${condition.conditionType}`;
  }
};

const getVolumeOscFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  const labels: Record<string, string> = {
    'VOLUME_OSC_VALUE': '거래량 오실레이터 값', 'ZERO_LINE': '0선',
  };
  return labels[field] || field;
};

/**
 * LogicNode를 자연어로 변환
 */
export const nodeToNaturalLanguage = (node: LogicNode, indent: number = 0): string => {
  const indentStr = '  '.repeat(indent);
  
  if (node.type === 'CONDITION' && node.condition) {
    return `${indentStr}${conditionToNaturalLanguage(node.condition)}`;
  }
  
  if (node.type === 'AND') {
    const childTexts = node.children?.map(child => 
      nodeToNaturalLanguage(child, indent + 1)) || [];
    return `${indentStr}다음 조건을 모두 만족:\n${childTexts.join('\n')}`;
  }
  
  if (node.type === 'OR') {
    const childTexts = node.children?.map(child => 
      nodeToNaturalLanguage(child, indent + 1)) || [];
    return `${indentStr}다음 조건 중 하나 이상 만족:\n${childTexts.join('\n')}`;
  }
  
  if (node.type === 'NOT') {
    const childText = node.children?.[0] ? 
      nodeToNaturalLanguage(node.children[0], indent + 1) : '';
    return `${indentStr}다음 조건의 반대:\n${childText}`;
  }
  
  return `${indentStr}알 수 없는 노드`;
};

/**
 * Condition을 자연어로 변환
 */
export const conditionToNaturalLanguage = (condition: ConditionDSL): string => {
  // 일목균형표 조건인 경우
  if (condition.indicatorType === 'ICHIMOKU') {
    return formatIchimokuCondition(condition);
  }
  
  // 볼린저밴드 조건인 경우
  if (condition.indicatorType === 'BOLLINGER') {
    return formatBollingerCondition(condition);
  }
  
  // MACD 조건인 경우
  if (condition.indicatorType === 'MACD') {
    return formatMacdCondition(condition);
  }
  
  // RSI 조건인 경우
  if (condition.indicatorType === 'RSI') {
    return formatRsiCondition(condition);
  }
  
  // Stochastic 조건인 경우
  if (condition.indicatorType === 'STOCHASTIC') {
    return formatStochasticCondition(condition);
  }
  
  // CCI 조건인 경우
  if (condition.indicatorType === 'CCI') {
    return formatCciCondition(condition);
  }
  
  // ADX 조건인 경우
  if (condition.indicatorType === 'ADX') {
    return formatAdxCondition(condition);
  }
  
  // TRIX 조건인 경우
  if (condition.indicatorType === 'TRIX') {
    return formatTrixCondition(condition);
  }
  
  // DMI 조건인 경우
  if (condition.indicatorType === 'DMI') {
    return formatDmiCondition(condition);
  }
  
  // OBV 조건인 경우
  if (condition.indicatorType === 'OBV') {
    return formatObvCondition(condition);
  }
  
  // VOLUME 조건인 경우
  if (condition.indicatorType === 'VOLUME') {
    return formatVolumeCondition(condition);
  }
  
  // MA 조건인 경우
  if (condition.indicatorType === 'MA') {
    return formatMaCondition(condition);
  }
  
  // DISPARITY 조건인 경우
  if (condition.indicatorType === 'DISPARITY') {
    return formatDisparityCondition(condition);
  }
  
  // NEW_PSYCHOLOGICAL 조건인 경우
  if (condition.indicatorType === 'NEW_PSYCHOLOGICAL') {
    return formatNewPsychologicalCondition(condition);
  }
  
  // INVEST_PSYCHOLOGICAL 조건인 경우
  if (condition.indicatorType === 'INVEST_PSYCHOLOGICAL') {
    return formatInvestPsychologicalCondition(condition);
  }
  
  // WILLIAMS_R 조건인 경우
  if (condition.indicatorType === 'WILLIAMS_R') {
    return formatWilliamsRCondition(condition);
  }
  
  // BWI 조건인 경우
  if (condition.indicatorType === 'BWI') {
    return formatBwiCondition(condition);
  }
  
  // VR 조건인 경우
  if (condition.indicatorType === 'VR') {
    return formatVrCondition(condition);
  }
  
  // VOLUME_OSC 조건인 경우
  if (condition.indicatorType === 'VOLUME_OSC') {
    return formatVolumeOscCondition(condition);
  }
  
  const indicator = getIndicatorDisplayName(condition.indicatorType);
  const period = condition.period ? `(${condition.period})` : '';
  
  switch (condition.conditionType) {
    case 'CROSS_UP':
      return `${indicator}${period}가 ${condition.targetValue}을 상향 돌파`;
    case 'CROSS_DOWN':
      return `${indicator}${period}가 ${condition.targetValue}을 하향 돌파`;
    case 'GOLDEN_CROSS':
      return `${indicator}${period} 골든 크로스`;
    case 'DEAD_CROSS':
      return `${indicator}${period} 데드 크로스`;
    case 'ABOVE':
      return `${indicator}${period}가 ${condition.targetValue} 이상`;
    case 'BELOW':
      return `${indicator}${period}가 ${condition.targetValue} 이하`;
    case 'ABOVE_STRICT':
      return `${indicator}${period}가 ${condition.targetValue} 초과`;
    case 'BELOW_STRICT':
      return `${indicator}${period}가 ${condition.targetValue} 미만`;
    case 'BETWEEN':
      return `${indicator}${period}가 ${condition.targetValue}와 ${condition.secondaryValue} 사이`;
    case 'OVERBOUGHT':
      return `${indicator}${period} 과매수 구간`;
    case 'OVERSOLD':
      return `${indicator}${period} 과매도 구간`;
    case 'INCREASING':
      return `${indicator}${period} 상승 중`;
    case 'DECREASING':
      return `${indicator}${period} 하락 중`;
    default:
      return `${indicator}${period} ${condition.conditionType}`;
  }
};

/**
 * 일목균형표 조건을 자연어로 변환
 */
const formatIchimokuCondition = (condition: ConditionDSL): string => {
  const leftField = getIchimokuFieldLabel(condition.leftField);
  const rightField = getIchimokuFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    // 기본 비교형
    case 'GT':
      return `${leftField} > ${rightField}`;
    case 'LT':
      return `${leftField} < ${rightField}`;
    case 'GTE':
      return `${leftField} >= ${rightField}`;
    case 'LTE':
      return `${leftField} <= ${rightField}`;
    case 'EQ':
      return `${leftField} == ${rightField}`;
    case 'NEQ':
      return `${leftField} != ${rightField}`;
    
    // 교차형
    case 'CROSS_UP':
      return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN':
      return `${leftField} 하향돌파 ${rightField}`;
    
    // 구름 위치형
    case 'ABOVE_CLOUD':
      return '가격이 구름 위';
    case 'BELOW_CLOUD':
      return '가격이 구름 아래';
    case 'IN_CLOUD':
      return '가격이 구름 안';
    case 'CLOUD_BREAK_UP':
      return '구름 상향 돌파';
    case 'CLOUD_BREAK_DOWN':
      return '구름 하향 돌파';
    
    // 구름 전환
    case 'SPAN1_GT_SPAN2':
      return '선행스팬1 > 선행스팬2';
    case 'SPAN1_LT_SPAN2':
      return '선행스팬1 < 선행스팬2';
    case 'SPAN1_CROSS_UP_SPAN2':
      return '선행스팬1 상향돌파 선행스팬2';
    case 'SPAN1_CROSS_DOWN_SPAN2':
      return '선행스팬1 하향돌파 선행스팬2';
    
    // 후행스팬 위치
    case 'LAGGING_GT_PRICE':
      return '후행스팬 > 26일전 가격';
    case 'LAGGING_LT_PRICE':
      return '후행스팬 < 26일전 가격';
    
    // 기울기형
    case 'SLOPE_UP':
      return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN':
      return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    
    // 차이형
    case 'DIFF_GT':
      return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT':
      return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    
    // 유지형
    case 'HOLD_N_DAYS':
      return `조건 ${condition.holdDays}일 연속 유지`;
    
    default:
      return `일목균형표 - ${condition.conditionType}`;
  }
};

/**
 * 일목균형표 필드 라벨 조회
 */
const getIchimokuFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  
  const labels: Record<string, string> = {
    'CONVERSION_LINE': '전환선',
    'BASE_LINE': '기준선',
    'LEADING_SPAN1': '선행스팬1',
    'LEADING_SPAN2': '선행스팬2',
    'LAGGING_SPAN': '후행스팬',
    'CLOSE_PRICE': '종가',
    'OPEN_PRICE': '시가',
    'HIGH_PRICE': '고가',
    'LOW_PRICE': '저가',
  };
  
  return labels[field] || field;
};

/**
 * 볼린저밴드 조건을 자연어로 변환
 */
const formatBollingerCondition = (condition: ConditionDSL): string => {
  const leftField = getBollingerFieldLabel(condition.leftField);
  const rightField = getBollingerFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    // 기본 비교형
    case 'GT':
      return `${leftField} > ${rightField}`;
    case 'LT':
      return `${leftField} < ${rightField}`;
    case 'GTE':
      return `${leftField} >= ${rightField}`;
    case 'LTE':
      return `${leftField} <= ${rightField}`;
    case 'EQ':
      return `${leftField} == ${rightField}`;
    case 'NEQ':
      return `${leftField} != ${rightField}`;
    
    // 교차형
    case 'CROSS_UP':
      return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN':
      return `${leftField} 하향돌파 ${rightField}`;
    
    // 기울기형
    case 'SLOPE_UP':
      return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN':
      return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    
    // 차이형
    case 'DIFF_GT':
      return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT':
      return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    
    // 유지형
    case 'HOLD_N_DAYS':
      return `조건 ${condition.holdDays}일 연속 유지`;
    
    default:
      return `볼린저밴드 - ${condition.conditionType}`;
  }
};

/**
 * 볼린저밴드 필드 라벨 조회
 */
const getBollingerFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  
  const labels: Record<string, string> = {
    'UPPER_BAND': '상단밴드',
    'MIDDLE_BAND': '중심선',
    'LOWER_BAND': '하단밴드',
    'CLOSE_PRICE': '종가',
    'OPEN_PRICE': '시가',
    'HIGH_PRICE': '고가',
    'LOW_PRICE': '저가',
  };
  
  return labels[field] || field;
};

/**
 * MACD 조건을 자연어로 변환
 */
const formatMacdCondition = (condition: ConditionDSL): string => {
  const leftField = getMacdFieldLabel(condition.leftField);
  const rightField = getMacdFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT':
      return `${leftField} > ${rightField}`;
    case 'LT':
      return `${leftField} < ${rightField}`;
    case 'GTE':
      return `${leftField} >= ${rightField}`;
    case 'LTE':
      return `${leftField} <= ${rightField}`;
    case 'EQ':
      return `${leftField} == ${rightField}`;
    case 'NEQ':
      return `${leftField} != ${rightField}`;
    case 'CROSS_UP':
      return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN':
      return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP':
      return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN':
      return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT':
      return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT':
      return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS':
      return `조건 ${condition.holdDays}일 연속 유지`;
    default:
      return `MACD - ${condition.conditionType}`;
  }
};

/**
 * MACD 필드 라벨 조회
 */
const getMacdFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  
  const labels: Record<string, string> = {
    'MACD_LINE': 'MACD 라인',
    'SIGNAL_LINE': '시그널 라인',
    'HISTOGRAM': '히스토그램',
    'ZERO_LINE': '0선',
  };
  
  return labels[field] || field;
};

/**
 * RSI 조건을 자연어로 변환
 */
const formatRsiCondition = (condition: ConditionDSL): string => {
  const leftField = getRsiFieldLabel(condition.leftField);
  const rightField = getRsiFieldLabel(condition.rightField);
  
  switch (condition.conditionType) {
    case 'GT': return `${leftField} > ${rightField}`;
    case 'LT': return `${leftField} < ${rightField}`;
    case 'GTE': return `${leftField} >= ${rightField}`;
    case 'LTE': return `${leftField} <= ${rightField}`;
    case 'EQ': return `${leftField} == ${rightField}`;
    case 'NEQ': return `${leftField} != ${rightField}`;
    case 'CROSS_UP': return `${leftField} 상향돌파 ${rightField}`;
    case 'CROSS_DOWN': return `${leftField} 하향돌파 ${rightField}`;
    case 'SLOPE_UP': return `${leftField} 상승 기울기 (${condition.slopePeriod}일)`;
    case 'SLOPE_DOWN': return `${leftField} 하락 기울기 (${condition.slopePeriod}일)`;
    case 'DIFF_GT': return `(${leftField} - ${rightField}) > ${condition.compareValue}`;
    case 'DIFF_LT': return `(${leftField} - ${rightField}) < ${condition.compareValue}`;
    case 'HOLD_N_DAYS': return `조건 ${condition.holdDays}일 연속 유지`;
    default: return `RSI - ${condition.conditionType}`;
  }
};

/**
 * RSI 필드 라벨 조회
 */
const getRsiFieldLabel = (field?: string): string => {
  if (!field || field === 'NONE') return '';
  
  const labels: Record<string, string> = {
    'RSI_VALUE': 'RSI 값',
    'OVERBOUGHT_70': '과매수선(70)',
    'NEUTRAL_50': '중립선(50)',
    'OVERSOLD_30': '과매도선(30)',
  };
  
  return labels[field] || field;
};

/**
 * 지표 표시 이름 조회
 */
export const getIndicatorDisplayName = (type: string): string => {
  const displayNames: Record<string, string> = {
    CCI: 'CCI',
    MACD: 'MACD',
    RSI: 'RSI',
    STOCHASTIC: 'Stochastic',
    ADX: 'ADX',
    TRIX: 'TRIX',
    DMI: 'DMI',
    OBV: 'OBV',
    VOLUME: '거래량',
    BWI: '볼린저 밴드 %B',
    DISPARITY: '이격도',
    WILLIAMS_R: 'Williams %R',
    VR: 'VR',
    VOLUME_OSC: 'VolumeOSC',
    NEW_PSYCHOLOGICAL: '신심리도',
    INVEST_PSYCHOLOGICAL: '투자심리도',
    ICHIMOKU: '일목균형표',
  };
  
  return displayNames[type] || type;
};

/**
 * 노드 개수 계산 (재귀)
 */
export const countNodes = (node: LogicNode): number => {
  let count = 1; // 자신
  
  if (node.children) {
    for (const child of node.children) {
      count += countNodes(child);
    }
  }
  
  return count;
};

/**
 * 조건 개수 계산
 */
export const countConditions = (node: LogicNode): number => {
  if (node.type === 'CONDITION') {
    return 1;
  }
  
  let count = 0;
  if (node.children) {
    for (const child of node.children) {
      count += countConditions(child);
    }
  }
  
  return count;
};

/**
 * 최대 깊이 계산
 */
export const getMaxDepth = (node: LogicNode): number => {
  if (!node.children || node.children.length === 0) {
    return 1;
  }
  
  let maxChildDepth = 0;
  for (const child of node.children) {
    maxChildDepth = Math.max(maxChildDepth, getMaxDepth(child));
  }
  
  return 1 + maxChildDepth;
};

// ============================================================
// 전략 검증 로직
// ============================================================

/**
 * 검증 오류 인터페이스
 */
export interface ValidationError {
  nodeId: string;
  type: 'error' | 'warning';
  message: string;
}

/**
 * 검증 결과 인터페이스
 */
export interface ValidationResult {
  isValid: boolean;
  errors: ValidationError[];
  warnings: ValidationError[];
}

/**
 * 단일 노드 검증
 */
const validateNode = (node: LogicNode, errors: ValidationError[], warnings: ValidationError[]): void => {
  // 1. ID 검증
  if (!node.id || node.id.trim() === '') {
    errors.push({
      nodeId: 'unknown',
      type: 'error',
      message: '노드 ID가 없습니다.'
    });
    return;
  }

  // 2. Type 검증
  if (!node.type) {
    errors.push({
      nodeId: node.id,
      type: 'error',
      message: '노드 타입이 지정되지 않았습니다.'
    });
    return;
  }

  // 3. CONDITION 노드 검증
  if (node.type === 'CONDITION') {
    if (!node.condition) {
      errors.push({
        nodeId: node.id,
        type: 'error',
        message: '조건 노드에 조건(condition)이 없습니다.'
      });
      return;
    }

    // 조건 필드 검증
    const condition = node.condition;
    
    if (!condition.indicatorType || condition.indicatorType.trim() === '') {
      errors.push({
        nodeId: node.id,
        type: 'error',
        message: '지표 타입(indicatorType)이 지정되지 않았습니다.'
      });
    }

    if (!condition.conditionType || condition.conditionType.trim() === '') {
      errors.push({
        nodeId: node.id,
        type: 'error',
        message: '조건 타입(conditionType)이 지정되지 않았습니다.'
      });
    }

    // 일목균형표 및 CommonOperator 기반 지표 검증
    const commonOperatorIndicators = [
      'ICHIMOKU', 'BOLLINGER', 'MACD', 'RSI', 'STOCHASTIC', 'CCI', 'ADX', 'TRIX',
      'DMI', 'OBV', 'VOLUME', 'MA', 'DISPARITY', 'NEW_PSYCHOLOGICAL', 
      'INVEST_PSYCHOLOGICAL', 'WILLIAMS_R', 'BWI', 'VR', 'VOLUME_OSC'
    ];

    if (commonOperatorIndicators.includes(condition.indicatorType)) {
      const condType = condition.conditionType;
      
      // GT, LT, GTE, LTE, EQ, NEQ, CROSS_UP, CROSS_DOWN - leftField, rightField 필수
      if (['GT', 'LT', 'GTE', 'LTE', 'EQ', 'NEQ', 'CROSS_UP', 'CROSS_DOWN'].includes(condType)) {
        if (!condition.leftField || condition.leftField === 'NONE') {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 조건대상1(leftField)이 필요합니다.`
          });
        }
        if (!condition.rightField || condition.rightField === 'NONE') {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 조건대상2(rightField)가 필요합니다.`
          });
        }
      }

      // SLOPE_UP, SLOPE_DOWN - leftField, slopePeriod 필수
      if (['SLOPE_UP', 'SLOPE_DOWN'].includes(condType)) {
        if (!condition.leftField || condition.leftField === 'NONE') {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 조건대상1(leftField)이 필요합니다.`
          });
        }
        if (!condition.slopePeriod || condition.slopePeriod <= 0) {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 기울기 기간(slopePeriod)이 필요합니다.`
          });
        }
      }

      // DIFF_GT, DIFF_LT - leftField, rightField, compareValue 필수
      if (['DIFF_GT', 'DIFF_LT'].includes(condType)) {
        if (!condition.leftField || condition.leftField === 'NONE') {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 조건대상1(leftField)이 필요합니다.`
          });
        }
        if (!condition.rightField || condition.rightField === 'NONE') {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 조건대상2(rightField)가 필요합니다.`
          });
        }
        if (condition.compareValue === undefined || condition.compareValue === null) {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: `${condType} 조건은 비교값(compareValue)이 필요합니다.`
          });
        }
      }

      // HOLD_N_DAYS - holdDays 필수
      if (condType === 'HOLD_N_DAYS') {
        if (!condition.holdDays || condition.holdDays <= 0 || condition.holdDays > 30) {
          errors.push({
            nodeId: node.id,
            type: 'error',
            message: 'HOLD_N_DAYS 조건은 유지일수(holdDays)가 1~30 범위여야 합니다.'
          });
        }
      }
    }
  }

  // 4. 논리 연산자 노드 검증
  if (node.type === 'NOT') {
    if (!node.children || node.children.length === 0) {
      errors.push({
        nodeId: node.id,
        type: 'error',
        message: 'NOT 연산자는 자식 노드가 필요합니다.'
      });
    } else if (node.children.length > 1) {
      errors.push({
        nodeId: node.id,
        type: 'error',
        message: 'NOT 연산자는 자식 노드가 1개만 있어야 합니다.'
      });
    }
  }

  if (node.type === 'AND' || node.type === 'OR') {
    if (!node.children || node.children.length === 0) {
      errors.push({
        nodeId: node.id,
        type: 'error',
        message: `${node.type} 연산자는 최소 1개 이상의 자식 노드가 필요합니다.`
      });
    } else if (node.children.length === 1) {
      warnings.push({
        nodeId: node.id,
        type: 'warning',
        message: `${node.type} 연산자에 자식 노드가 1개만 있습니다. 의미가 없을 수 있습니다.`
      });
    }
  }

  // 5. 자식 노드 재귀 검증
  if (node.children) {
    for (const child of node.children) {
      validateNode(child, errors, warnings);
    }
  }
};

/**
 * 전략 트리 검증
 */
export const validateStrategyTree = (node: LogicNode | null): ValidationResult => {
  const errors: ValidationError[] = [];
  const warnings: ValidationError[] = [];

  if (!node) {
    return {
      isValid: true,
      errors: [],
      warnings: []
    };
  }

  validateNode(node, errors, warnings);

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