// 전략 평가 Web Worker
// 별도 스레드에서 전략 조건 평가를 수행하여 메인 UI 스레드 블로킹 방지

interface StrategyConditionDto {
  id?: number;
  indicatorType: string;
  conditionType: string;
  targetValue?: number;
  targetValue2?: number;
  description?: string;
  enabled?: boolean;
}

interface ConditionGroupDto {
  id?: number;
  name?: string;
  logicalOperator: 'AND' | 'OR';
  conditions: StrategyConditionDto[];
  childGroups?: ConditionGroupDto[];
  groupType?: 'BUY' | 'SELL';
  signalType?: string;
}

interface StrategyRuleDto {
  id: number;
  name: string;
  enabled: boolean;
  conditionGroups: ConditionGroupDto[];
  buyConditionGroups?: ConditionGroupDto[];
  sellConditionGroups?: ConditionGroupDto[];
  enableMaBuy?: boolean;
  enableAuxBuy?: boolean;
  totalConditionCount?: number;
  conditionSummary?: string;
}

interface EvaluationMessage {
  type: 'evaluate';
  strategies: StrategyRuleDto[];
  currentData: any;
  prevData: any | null;
  currentIndex: number;
  referenceTime: string;
}

interface ConditionResult {
  description: string;
  matched: boolean;
}

interface EvaluationResult {
  buy: {
    total: number;
    matched: number;
    percentage: number;
    conditions: ConditionResult[];
  };
  sell: {
    total: number;
    matched: number;
    percentage: number;
    conditions: ConditionResult[];
  };
}

interface StrategyEvaluationResult {
  strategyId: number;
  strategyName: string;
  enabled: boolean;
  evaluation: EvaluationResult;
}

interface WorkerResponse {
  type: 'result';
  results: StrategyEvaluationResult[];
  currentIndex: number;
  referenceTime: string;
}

// 단일 조건 평가 함수
function evaluateCondition(
  condition: StrategyConditionDto,
  currentData: any,
  prevData: any | null
): boolean {
  if (!currentData || condition.enabled === false) return false;
  
  const { indicatorType, conditionType, targetValue, targetValue2 } = condition;
  
  try {
    switch (indicatorType) {
      case 'RSI': {
        const rsiValue = currentData.rsi;
        const prevRsi = prevData?.rsi;
        if (rsiValue == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return rsiValue > (targetValue || 50);
          case 'BELOW': return rsiValue < (targetValue || 50);
          case 'CROSS_UP': return prevRsi != null && prevRsi <= (targetValue || 50) && rsiValue > (targetValue || 50);
          case 'CROSS_DOWN': return prevRsi != null && prevRsi >= (targetValue || 50) && rsiValue < (targetValue || 50);
          case 'OVERBOUGHT': return rsiValue >= (targetValue || 70);
          case 'OVERSOLD': return rsiValue <= (targetValue || 30);
          case 'RANGE': return rsiValue >= (targetValue || 30) && rsiValue <= (targetValue2 || 70);
          default: return false;
        }
      }
      
      case 'STOCHASTIC':
      case 'STOCHASTIC_K':
      case 'STOCHASTIC_D': {
        const kValue = currentData.stochasticK;
        const dValue = currentData.stochasticD;
        const prevK = prevData?.stochasticK;
        const prevD = prevData?.stochasticD;
        const value = indicatorType === 'STOCHASTIC_D' ? dValue : kValue;
        const prevValue = indicatorType === 'STOCHASTIC_D' ? prevD : prevK;
        
        if (value == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return value > (targetValue || 50);
          case 'BELOW': return value < (targetValue || 50);
          case 'CROSS_UP': return prevValue != null && prevValue <= (targetValue || 50) && value > (targetValue || 50);
          case 'CROSS_DOWN': return prevValue != null && prevValue >= (targetValue || 50) && value < (targetValue || 50);
          case 'GOLDEN_CROSS': return prevK != null && prevD != null && kValue != null && dValue != null && prevK <= prevD && kValue > dValue;
          case 'DEAD_CROSS': return prevK != null && prevD != null && kValue != null && dValue != null && prevK >= prevD && kValue < dValue;
          case 'OVERBOUGHT': return value >= (targetValue || 80);
          case 'OVERSOLD': return value <= (targetValue || 20);
          default: return false;
        }
      }
      
      case 'MACD':
      case 'MACD_LINE':
      case 'MACD_SIGNAL':
      case 'MACD_HISTOGRAM': {
        const macdLine = currentData.macdLine;
        const signalLine = currentData.signalLine;
        const histogram = currentData.macdHistogram;
        const prevMacd = prevData?.macdLine;
        const prevSignal = prevData?.signalLine;
        const prevHist = prevData?.macdHistogram;
        
        let value: number | null = null;
        let prevValue: number | null = null;
        
        if (indicatorType === 'MACD_SIGNAL') {
          value = signalLine;
          prevValue = prevSignal;
        } else if (indicatorType === 'MACD_HISTOGRAM') {
          value = histogram;
          prevValue = prevHist;
        } else {
          value = macdLine;
          prevValue = prevMacd;
        }
        
        if (value == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return value > (targetValue || 0);
          case 'BELOW': return value < (targetValue || 0);
          case 'CROSS_UP': return prevValue != null && prevValue <= (targetValue || 0) && value > (targetValue || 0);
          case 'CROSS_DOWN': return prevValue != null && prevValue >= (targetValue || 0) && value < (targetValue || 0);
          case 'GOLDEN_CROSS': return prevMacd != null && prevSignal != null && macdLine != null && signalLine != null && prevMacd <= prevSignal && macdLine > signalLine;
          case 'DEAD_CROSS': return prevMacd != null && prevSignal != null && macdLine != null && signalLine != null && prevMacd >= prevSignal && macdLine < signalLine;
          case 'HISTOGRAM_POSITIVE': return histogram != null && histogram > 0;
          case 'HISTOGRAM_NEGATIVE': return histogram != null && histogram < 0;
          case 'HISTOGRAM_INCREASING': return histogram != null && prevHist != null && histogram > prevHist;
          case 'HISTOGRAM_DECREASING': return histogram != null && prevHist != null && histogram < prevHist;
          default: return false;
        }
      }
      
      case 'ADX': {
        const adxValue = currentData.adx;
        if (adxValue == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return adxValue > (targetValue || 25);
          case 'BELOW': return adxValue < (targetValue || 25);
          case 'STRONG_TREND': return adxValue >= (targetValue || 25);
          case 'WEAK_TREND': return adxValue < (targetValue || 20);
          default: return false;
        }
      }
      
      case 'BOLLINGER':
      case 'BOLLINGER_UPPER':
      case 'BOLLINGER_LOWER':
      case 'BOLLINGER_MIDDLE': {
        const close = currentData.close;
        const upper = currentData.bollingerUpper;
        const lower = currentData.bollingerLower;
        const middle = currentData.bollingerMiddle;
        
        if (close == null) return false;
        
        switch (conditionType) {
          case 'ABOVE_UPPER': return upper != null && close > upper;
          case 'BELOW_LOWER': return lower != null && close < lower;
          case 'TOUCH_UPPER': return upper != null && Math.abs(close - upper) / upper < 0.001;
          case 'TOUCH_LOWER': return lower != null && Math.abs(close - lower) / lower < 0.001;
          case 'INSIDE_BANDS': return upper != null && lower != null && close <= upper && close >= lower;
          case 'ABOVE_MIDDLE': return middle != null && close > middle;
          case 'BELOW_MIDDLE': return middle != null && close < middle;
          default: return false;
        }
      }
      
      case 'MA':
      case 'MA5':
      case 'MA10':
      case 'MA20':
      case 'MA60':
      case 'MA120': {
        const close = currentData.close;
        const prevClose = prevData?.close;
        
        let maValue: number | null = null;
        let prevMa: number | null = null;
        
        switch (indicatorType) {
          case 'MA5': maValue = currentData.ma5; prevMa = prevData?.ma5; break;
          case 'MA10': maValue = currentData.ma10; prevMa = prevData?.ma10; break;
          case 'MA20': maValue = currentData.ma20; prevMa = prevData?.ma20; break;
          case 'MA60': maValue = currentData.ma60; prevMa = prevData?.ma60; break;
          case 'MA120': maValue = currentData.ma120; prevMa = prevData?.ma120; break;
          default: maValue = currentData.ma20; prevMa = prevData?.ma20;
        }
        
        if (close == null || maValue == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return close > maValue;
          case 'BELOW': return close < maValue;
          case 'CROSS_UP': return prevClose != null && prevMa != null && prevClose <= prevMa && close > maValue;
          case 'CROSS_DOWN': return prevClose != null && prevMa != null && prevClose >= prevMa && close < maValue;
          case 'GOLDEN_CROSS': {
            // 단기MA > 장기MA 교차
            const shortMa = currentData.ma5 || currentData.ma10;
            const longMa = currentData.ma20 || currentData.ma60;
            const prevShort = prevData?.ma5 || prevData?.ma10;
            const prevLong = prevData?.ma20 || prevData?.ma60;
            return shortMa != null && longMa != null && prevShort != null && prevLong != null && 
                   prevShort <= prevLong && shortMa > longMa;
          }
          case 'DEAD_CROSS': {
            const shortMa = currentData.ma5 || currentData.ma10;
            const longMa = currentData.ma20 || currentData.ma60;
            const prevShort = prevData?.ma5 || prevData?.ma10;
            const prevLong = prevData?.ma20 || prevData?.ma60;
            return shortMa != null && longMa != null && prevShort != null && prevLong != null && 
                   prevShort >= prevLong && shortMa < longMa;
          }
          case 'UPTREND': return maValue > (prevMa || 0);
          case 'DOWNTREND': return maValue < (prevMa || Infinity);
          default: return false;
        }
      }
      
      case 'PRICE': {
        const close = currentData.close;
        const prevClose = prevData?.close;
        
        if (close == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return close > (targetValue || 0);
          case 'BELOW': return close < (targetValue || 0);
          case 'CHANGE_PERCENT': {
            if (prevClose == null) return false;
            const changePercent = ((close - prevClose) / prevClose) * 100;
            return changePercent >= (targetValue || 0);
          }
          case 'RANGE': return close >= (targetValue || 0) && close <= (targetValue2 || Infinity);
          default: return false;
        }
      }
      
      case 'VOLUME': {
        const volume = currentData.volume;
        const prevVolume = prevData?.volume;
        
        if (volume == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return volume > (targetValue || 0);
          case 'ABOVE_AVERAGE': {
            const avgVolume = currentData.volumeAvg || currentData.volumeMa20;
            return avgVolume != null && volume > avgVolume * (targetValue || 1);
          }
          case 'INCREASING': return prevVolume != null && volume > prevVolume;
          case 'SPIKE': {
            const avgVolume = currentData.volumeAvg || currentData.volumeMa20;
            return avgVolume != null && volume > avgVolume * (targetValue || 2);
          }
          default: return false;
        }
      }
      
      case 'CCI': {
        const cciValue = currentData.cci;
        const cciSignal = currentData.cciSignal;
        const prevCci = prevData?.cci;
        const prevCciSignal = prevData?.cciSignal;
        
        if (cciValue == null) return false;
        
        switch (conditionType) {
          case 'ABOVE': return cciValue > (targetValue || 0);
          case 'BELOW': return cciValue < (targetValue || 0);
          case 'CROSS_UP': {
            // targetValue가 있으면 해당 값 돌파, 없으면 -100/0/100 중 하나라도 돌파
            if (targetValue != null) {
              return prevCci != null && prevCci <= targetValue && cciValue > targetValue;
            } else {
              // 침체(-100), 중앙(0), 과열(100) 중 하나라도 상향 돌파
              const crossOversold = prevCci != null && prevCci < -100 && cciValue >= -100;
              const crossMiddle = prevCci != null && prevCci < 0 && cciValue >= 0;
              const crossOverbought = prevCci != null && prevCci < 100 && cciValue >= 100;
              return crossOversold || crossMiddle || crossOverbought;
            }
          }
          case 'CROSS_DOWN': {
            // targetValue가 있으면 해당 값 돌파, 없으면 -100/0/100 중 하나라도 돌파
            if (targetValue != null) {
              return prevCci != null && prevCci >= targetValue && cciValue < targetValue;
            } else {
              // 침체(-100), 중앙(0), 과열(100) 중 하나라도 하향 돌파
              const crossOverbought = prevCci != null && prevCci > 100 && cciValue <= 100;
              const crossMiddle = prevCci != null && prevCci > 0 && cciValue <= 0;
              const crossOversold = prevCci != null && prevCci > -100 && cciValue <= -100;
              return crossOverbought || crossMiddle || crossOversold;
            }
          }
          case 'GOLDEN_CROSS': 
            // CCI가 CCI Signal을 상향 돌파
            return cciSignal != null && prevCci != null && prevCciSignal != null && 
                   prevCci <= prevCciSignal && cciValue > cciSignal;
          case 'DEAD_CROSS':
            // CCI가 CCI Signal을 하향 돌파
            return cciSignal != null && prevCci != null && prevCciSignal != null && 
                   prevCci >= prevCciSignal && cciValue < cciSignal;
          case 'OVERBOUGHT': return cciValue >= (targetValue || 100);
          case 'OVERSOLD': return cciValue <= (targetValue || -100);
          default: return false;
        }
      }
      
      case 'WILLIAMS_R': {
        const wrValue = currentData.williamsR;
        if (wrValue == null) return false;
        
        switch (conditionType) {
          case 'OVERBOUGHT': return wrValue >= (targetValue || -20);
          case 'OVERSOLD': return wrValue <= (targetValue || -80);
          case 'ABOVE': return wrValue > (targetValue || -50);
          case 'BELOW': return wrValue < (targetValue || -50);
          default: return false;
        }
      }
      
      default:
        return false;
    }
  } catch (error) {
    console.error('Worker: 조건 평가 오류:', error);
    return false;
  }
}

// 조건 그룹 평가 함수
function evaluateConditionGroup(
  group: ConditionGroupDto,
  currentData: any,
  prevData: any | null
): { total: number; matched: number; conditions: ConditionResult[] } {
  const results: ConditionResult[] = [];
  let total = 0;
  let matched = 0;
  
  const groupAny = group as any;
  const conditions = group.conditions || groupAny.strategyConditions || [];
  
  for (const condition of conditions) {
    if (condition.enabled === false) continue;
    
    const isMatched = evaluateCondition(condition, currentData, prevData);
    const description = condition.description || 
      `${condition.indicatorType} ${condition.conditionType}${condition.targetValue ? ` ${condition.targetValue}` : ''}`;
    results.push({ description, matched: isMatched });
    total++;
    if (isMatched) matched++;
  }
  
  const childGroups = group.childGroups || groupAny.children || [];
  for (const childGroup of childGroups) {
    const childResult = evaluateConditionGroup(childGroup, currentData, prevData);
    total += childResult.total;
    matched += childResult.matched;
    results.push(...childResult.conditions);
  }
  
  return { total, matched, conditions: results };
}

// 전략 규칙 평가 함수
function evaluateStrategyRule(
  rule: StrategyRuleDto,
  currentData: any,
  prevData: any | null
): EvaluationResult {
  const buyResult = { total: 0, matched: 0, percentage: 0, conditions: [] as ConditionResult[] };
  const sellResult = { total: 0, matched: 0, percentage: 0, conditions: [] as ConditionResult[] };
  
  // buyConditionGroups 처리
  if (rule.buyConditionGroups && rule.buyConditionGroups.length > 0) {
    for (const group of rule.buyConditionGroups) {
      const result = evaluateConditionGroup(group, currentData, prevData);
      buyResult.total += result.total;
      buyResult.matched += result.matched;
      buyResult.conditions.push(...result.conditions);
    }
  }
  
  // sellConditionGroups 처리
  if (rule.sellConditionGroups && rule.sellConditionGroups.length > 0) {
    for (const group of rule.sellConditionGroups) {
      const result = evaluateConditionGroup(group, currentData, prevData);
      sellResult.total += result.total;
      sellResult.matched += result.matched;
      sellResult.conditions.push(...result.conditions);
    }
  }
  
  // 기존 conditionGroups 처리
  if (rule.conditionGroups && rule.conditionGroups.length > 0) {
    for (const group of rule.conditionGroups) {
      const result = evaluateConditionGroup(group, currentData, prevData);
      const groupAny = group as any;
      const isBuy = group.groupType === 'BUY' || groupAny.signalType === 'BUY';
      const isSell = group.groupType === 'SELL' || groupAny.signalType === 'SELL';
      
      if (isSell) {
        sellResult.total += result.total;
        sellResult.matched += result.matched;
        sellResult.conditions.push(...result.conditions);
      } else {
        buyResult.total += result.total;
        buyResult.matched += result.matched;
        buyResult.conditions.push(...result.conditions);
      }
    }
  }
  
  // 비율 계산
  buyResult.percentage = buyResult.total > 0 ? Math.round((buyResult.matched / buyResult.total) * 100) : 0;
  sellResult.percentage = sellResult.total > 0 ? Math.round((sellResult.matched / sellResult.total) * 100) : 0;
  
  return { buy: buyResult, sell: sellResult };
}

// Worker 메시지 핸들러
self.onmessage = (event: MessageEvent<EvaluationMessage>) => {
  const { type, strategies, currentData, prevData, currentIndex, referenceTime } = event.data;
  
  if (type !== 'evaluate') return;
  
  try {
    const results: StrategyEvaluationResult[] = strategies.map(strategy => ({
      strategyId: strategy.id,
      strategyName: strategy.name,
      enabled: strategy.enabled,
      evaluation: evaluateStrategyRule(strategy, currentData, prevData)
    }));
    
    const response: WorkerResponse = {
      type: 'result',
      results,
      currentIndex,
      referenceTime
    };
    
    self.postMessage(response);
  } catch (error) {
    console.error('Worker: 전략 평가 오류:', error);
    self.postMessage({
      type: 'error',
      error: String(error),
      currentIndex,
      referenceTime
    });
  }
};

export {};

