/**
 * 추세 강도(정배열/역배열) 계산 유틸리티
 * 
 * 정배열: 단기 이동평균 > 중기 이동평균 > 장기 이동평균 (상승 추세)
 * 역배열: 단기 이동평균 < 중기 이동평균 < 장기 이동평균 (하락 추세)
 * 
 * 공식:
 * S = ((MA10 - MA60) + (MA20 - MA60)) / ATR(14)
 * TrendStrength = tanh(S) * 100
 * 
 * 결과: -100 ~ +100
 * - +100에 가까움: 강한 정배열(상승추세)
 * - -100에 가까움: 강한 역배열(하락추세)
 * - 0 근처: 추세 약함 또는 혼조
 */

// OHLC 캔들 데이터 인터페이스
export interface OHLCData {
  open: number;
  high: number;
  low: number;
  close: number;
  volume?: number;
  timestamp?: string;
}

// 추세 강도 결과 인터페이스
export interface TrendStrengthResult {
  symbol: string;
  koreanName: string;
  englishName?: string;
  trendStrength: number;  // -100 ~ +100
  ma10: number;
  ma20: number;
  ma60: number;
  atr14: number;
  isFavorite?: boolean;
}

/**
 * 단순 이동평균(SMA) 계산
 * @param data 종가 배열
 * @param period 이동평균 기간
 * @returns 이동평균 값 (데이터가 부족하면 null)
 */
export function calculateSMA(data: number[], period: number): number | null {
  if (data.length < period) return null;
  
  const recentData = data.slice(-period);
  const sum = recentData.reduce((acc, val) => acc + val, 0);
  return sum / period;
}

/**
 * ATR(Average True Range) 계산
 * @param ohlcData OHLC 데이터 배열
 * @param period ATR 기간 (기본: 14)
 * @returns ATR 값 (데이터가 부족하면 null)
 */
export function calculateATR(ohlcData: OHLCData[], period: number = 14): number | null {
  if (ohlcData.length < period + 1) return null;
  
  const trueRanges: number[] = [];
  
  // True Range 계산 (최근 period+1개 데이터 사용)
  const recentData = ohlcData.slice(-(period + 1));
  
  for (let i = 1; i < recentData.length; i++) {
    const current = recentData[i];
    const previous = recentData[i - 1];
    
    // True Range = max(High - Low, |High - Previous Close|, |Low - Previous Close|)
    const tr = Math.max(
      current.high - current.low,
      Math.abs(current.high - previous.close),
      Math.abs(current.low - previous.close)
    );
    trueRanges.push(tr);
  }
  
  // ATR = SMA of True Ranges
  const atr = trueRanges.reduce((acc, val) => acc + val, 0) / trueRanges.length;
  return atr;
}

/**
 * 추세 강도 계산
 * 
 * 공식:
 * S = ((MA10 - MA60) + (MA20 - MA60)) / ATR(14)
 * TrendStrength = tanh(S) * 100
 * 
 * @param ohlcData OHLC 데이터 배열 (최소 60개 이상 필요)
 * @returns 추세 강도 (-100 ~ +100) 또는 null
 */
export function calculateTrendStrength(ohlcData: OHLCData[]): {
  trendStrength: number;
  ma10: number;
  ma20: number;
  ma60: number;
  atr14: number;
} | null {
  // 최소 60개 데이터 필요
  if (ohlcData.length < 60) {
    console.warn('추세 강도 계산에 최소 60개 데이터 필요');
    return null;
  }
  
  // 종가 배열 추출
  const closePrices = ohlcData.map(d => d.close);
  
  // 이동평균 계산
  const ma10 = calculateSMA(closePrices, 10);
  const ma20 = calculateSMA(closePrices, 20);
  const ma60 = calculateSMA(closePrices, 60);
  
  // ATR 계산
  const atr14 = calculateATR(ohlcData, 14);
  
  // 유효성 검사
  if (ma10 === null || ma20 === null || ma60 === null || atr14 === null || atr14 === 0) {
    return null;
  }
  
  // S 계산: ((MA10 - MA60) + (MA20 - MA60)) / ATR(14)
  const s = ((ma10 - ma60) + (ma20 - ma60)) / atr14;
  
  // TrendStrength = tanh(S) * 100
  const trendStrength = Math.tanh(s) * 100;
  
  return {
    trendStrength: Math.round(trendStrength * 100) / 100, // 소수점 2자리
    ma10: Math.round(ma10 * 100) / 100,
    ma20: Math.round(ma20 * 100) / 100,
    ma60: Math.round(ma60 * 100) / 100,
    atr14: Math.round(atr14 * 100) / 100,
  };
}

/**
 * 추세 강도에 따른 라벨 반환
 * @param strength 추세 강도 값
 * @returns 라벨 문자열
 */
export function getTrendLabel(strength: number): string {
  if (strength >= 80) return '매우 강한 정배열';
  if (strength >= 50) return '강한 정배열';
  if (strength >= 20) return '정배열';
  if (strength >= -20) return '중립';
  if (strength >= -50) return '역배열';
  if (strength >= -80) return '강한 역배열';
  return '매우 강한 역배열';
}

/**
 * 정배열 강도 계산 (0 ~ 100)
 * trendStrength가 양수일 때만 값이 있음
 * @param trendStrength 통합 추세 강도 (-100 ~ +100)
 * @returns 정배열 강도 (0 ~ 100)
 */
export function getBullishStrength(trendStrength: number): number {
  return Math.max(0, trendStrength);
}

/**
 * 역배열 강도 계산 (0 ~ 100)
 * trendStrength가 음수일 때만 값이 있음
 * @param trendStrength 통합 추세 강도 (-100 ~ +100)
 * @returns 역배열 강도 (0 ~ 100)
 */
export function getBearishStrength(trendStrength: number): number {
  return Math.max(0, -trendStrength);
}

/**
 * 정배열/역배열 강도 분리 반환
 * @param trendStrength 통합 추세 강도 (-100 ~ +100)
 * @returns { bullish: 정배열 강도, bearish: 역배열 강도 }
 */
export function getStrengthValues(trendStrength: number): { bullish: number; bearish: number } {
  return {
    bullish: getBullishStrength(trendStrength),
    bearish: getBearishStrength(trendStrength),
  };
}

/**
 * 추세 강도에 따른 색상 반환
 * @param strength 추세 강도 값
 * @returns 색상 코드
 */
export function getTrendColor(strength: number): string {
  if (strength >= 50) return '#c62828';  // 강한 상승 - 빨간색
  if (strength >= 20) return '#ef5350';  // 상승 - 연한 빨간색
  if (strength >= -20) return '#9e9e9e'; // 중립 - 회색
  if (strength >= -50) return '#42a5f5'; // 하락 - 연한 파란색
  return '#1565c0';  // 강한 하락 - 파란색
}

/**
 * 추세 강도 기준 정렬 함수
 * @param items 정렬할 항목 배열
 * @param sortMode 정렬 모드 ('default' | 'bullish' | 'bearish')
 * @returns 정렬된 배열
 */
export function sortByTrendStrength<T extends { trendStrength?: number; koreanName: string }>(
  items: T[],
  sortMode: 'default' | 'bullish' | 'bearish'
): T[] {
  const sorted = [...items];
  
  switch (sortMode) {
    case 'bullish':
      // 정배열: 추세 강도가 높은 순 (내림차순)
      return sorted.sort((a, b) => (b.trendStrength ?? 0) - (a.trendStrength ?? 0));
    
    case 'bearish':
      // 역배열: 추세 강도가 낮은 순 (오름차순)
      return sorted.sort((a, b) => (a.trendStrength ?? 0) - (b.trendStrength ?? 0));
    
    case 'default':
    default:
      // 기본: 이름순 정렬
      return sorted.sort((a, b) => a.koreanName.localeCompare(b.koreanName, 'ko'));
  }
}

/**
 * 배치 추세 강도 계산 (여러 종목 동시 처리)
 * @param symbolsWithData 종목별 OHLC 데이터 맵
 * @returns 추세 강도 결과 배열
 */
export function calculateBatchTrendStrength(
  symbolsWithData: Map<string, { 
    koreanName: string; 
    englishName?: string;
    ohlcData: OHLCData[];
    isFavorite?: boolean;
  }>
): TrendStrengthResult[] {
  const results: TrendStrengthResult[] = [];
  
  symbolsWithData.forEach((data, symbol) => {
    const strength = calculateTrendStrength(data.ohlcData);
    
    if (strength) {
      results.push({
        symbol,
        koreanName: data.koreanName,
        englishName: data.englishName,
        trendStrength: strength.trendStrength,
        ma10: strength.ma10,
        ma20: strength.ma20,
        ma60: strength.ma60,
        atr14: strength.atr14,
        isFavorite: data.isFavorite,
      });
    } else {
      // 데이터 부족 시 기본값
      results.push({
        symbol,
        koreanName: data.koreanName,
        englishName: data.englishName,
        trendStrength: 0,
        ma10: 0,
        ma20: 0,
        ma60: 0,
        atr14: 0,
        isFavorite: data.isFavorite,
      });
    }
  });
  
  return results;
}

// 사용 예시
/*
import { calculateTrendStrength, sortByTrendStrength, getTrendLabel, getTrendColor } from './trendStrength';

// 단일 종목 추세 강도 계산
const ohlcData = [
  { open: 100, high: 105, low: 98, close: 103 },
  { open: 103, high: 108, low: 101, close: 106 },
  // ... 최소 60개 데이터
];

const result = calculateTrendStrength(ohlcData);
if (result) {
  console.log(`추세 강도: ${result.trendStrength}`);
  console.log(`라벨: ${getTrendLabel(result.trendStrength)}`);
  console.log(`색상: ${getTrendColor(result.trendStrength)}`);
}

// 여러 종목 정렬
const items = [
  { symbol: 'BTC', koreanName: '비트코인', trendStrength: 75 },
  { symbol: 'ETH', koreanName: '이더리움', trendStrength: -30 },
  { symbol: 'XRP', koreanName: '리플', trendStrength: 45 },
];

// 정배열 순 정렬 (상승 추세가 강한 순)
const bullishSorted = sortByTrendStrength(items, 'bullish');
// 결과: BTC(75) -> XRP(45) -> ETH(-30)

// 역배열 순 정렬 (하락 추세가 강한 순)
const bearishSorted = sortByTrendStrength(items, 'bearish');
// 결과: ETH(-30) -> XRP(45) -> BTC(75)
*/

