/**
 * 정배열/역배열 + Stochastic Slow 기반 매매 전략
 * 
 * [정배열/역배열 조건]
 * - 정배열: 추세 강도 > 0
 * - 역배열: 추세 강도 < 0
 * 
 * [매매 조건]
 * 1) 정배열인 경우:
 *    - Stochastic Slow 20 상향 돌파 → 매수
 *    - 50 상향 돌파 → 매수  
 *    - 80 상향 돌파 → 매수
 *    - 20 하향 돌파 → 매도
 *    - 50 하향 돌파 → 매도
 *    - 80 하향 돌파 → 매도
 * 
 * 2) 역배열인 경우:
 *    - 80 상향 돌파 → 매수
 *    - 80 하향 돌파 → 매도
 */

// OHLCV + 지표 데이터 인터페이스
export interface CandleWithIndicators {
  date: string;
  timestamp?: string;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
  stochasticK: number | null;  // Stochastic Slow %K
  stochasticD: number | null;  // Stochastic Slow %D
  macdLine?: number | null;
  signalLine?: number | null;
  macdHistogram?: number | null;
  trendStrength?: number;  // 추세 강도 (-100 ~ +100)
}

// 매매 신호 타입
export type SignalType = 'BUY' | 'SELL' | 'HOLD';

// 매매 신호 결과
export interface TradingSignal {
  date: string;
  signal: SignalType;
  reason: string;
  stochasticK: number;
  stochasticD: number;
  trendStrength: number;
  isBullish: boolean;  // 정배열 여부
  crossLevel?: number;  // 돌파 레벨 (20, 50, 80)
  crossDirection?: 'UP' | 'DOWN';  // 돌파 방향
}

// 돌파 레벨 정의
const OVERSOLD_LEVEL = 20;
const NEUTRAL_LEVEL = 50;
const OVERBOUGHT_LEVEL = 80;

/**
 * 상향 돌파 여부 확인
 * @param prevValue 이전 값
 * @param currValue 현재 값
 * @param level 돌파 레벨
 * @returns 상향 돌파 여부
 */
export function isCrossUp(prevValue: number, currValue: number, level: number): boolean {
  return prevValue < level && currValue >= level;
}

/**
 * 하향 돌파 여부 확인
 * @param prevValue 이전 값
 * @param currValue 현재 값
 * @param level 돌파 레벨
 * @returns 하향 돌파 여부
 */
export function isCrossDown(prevValue: number, currValue: number, level: number): boolean {
  return prevValue > level && currValue <= level;
}

/**
 * 정배열 여부 확인
 * @param trendStrength 추세 강도
 * @returns 정배열 여부 (추세 강도 > 0)
 */
export function isBullishTrend(trendStrength: number): boolean {
  return trendStrength > 0;
}

/**
 * 역배열 여부 확인
 * @param trendStrength 추세 강도
 * @returns 역배열 여부 (추세 강도 < 0)
 */
export function isBearishTrend(trendStrength: number): boolean {
  return trendStrength < 0;
}

/**
 * 단일 캔들에 대한 매매 신호 생성
 * @param current 현재 캔들 데이터
 * @param previous 이전 캔들 데이터
 * @param trendStrength 추세 강도
 * @returns 매매 신호 또는 null
 */
export function generateSignalForCandle(
  current: CandleWithIndicators,
  previous: CandleWithIndicators,
  trendStrength: number
): TradingSignal | null {
  // Stochastic 값이 없으면 신호 없음
  if (current.stochasticK === null || previous.stochasticK === null) {
    return null;
  }

  const currK = current.stochasticK;
  const prevK = previous.stochasticK;
  const isBullish = isBullishTrend(trendStrength);

  // 정배열인 경우
  if (isBullish) {
    // 20 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, OVERSOLD_LEVEL)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: '정배열 + Stochastic 20 상향 돌파 (과매도 탈출)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: OVERSOLD_LEVEL,
        crossDirection: 'UP',
      };
    }

    // 50 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, NEUTRAL_LEVEL)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: '정배열 + Stochastic 50 상향 돌파 (중립선 상향)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: NEUTRAL_LEVEL,
        crossDirection: 'UP',
      };
    }

    // 80 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, OVERBOUGHT_LEVEL)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: '정배열 + Stochastic 80 상향 돌파 (강한 상승 모멘텀)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: OVERBOUGHT_LEVEL,
        crossDirection: 'UP',
      };
    }

    // 20 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, OVERSOLD_LEVEL)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: '정배열 + Stochastic 20 하향 돌파 (과매도 진입)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: OVERSOLD_LEVEL,
        crossDirection: 'DOWN',
      };
    }

    // 50 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, NEUTRAL_LEVEL)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: '정배열 + Stochastic 50 하향 돌파 (중립선 하향)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: NEUTRAL_LEVEL,
        crossDirection: 'DOWN',
      };
    }

    // 80 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, OVERBOUGHT_LEVEL)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: '정배열 + Stochastic 80 하향 돌파 (과매수 이탈)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: OVERBOUGHT_LEVEL,
        crossDirection: 'DOWN',
      };
    }
  }
  // 역배열인 경우
  else if (isBearishTrend(trendStrength)) {
    // 80 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, OVERBOUGHT_LEVEL)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: '역배열 + Stochastic 80 상향 돌파 (반등 시그널)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: false,
        crossLevel: OVERBOUGHT_LEVEL,
        crossDirection: 'UP',
      };
    }

    // 80 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, OVERBOUGHT_LEVEL)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: '역배열 + Stochastic 80 하향 돌파 (하락 지속)',
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: false,
        crossLevel: OVERBOUGHT_LEVEL,
        crossDirection: 'DOWN',
      };
    }
  }

  // 신호 없음
  return null;
}

/**
 * 전체 캔들 데이터에 대한 매매 신호 생성
 * @param candles 캔들 데이터 배열 (시간순 정렬)
 * @param trendStrength 추세 강도 (현재 종목의 추세)
 * @returns 매매 신호 배열
 */
export function generateSignals(
  candles: CandleWithIndicators[],
  trendStrength: number
): TradingSignal[] {
  const signals: TradingSignal[] = [];

  if (candles.length < 2) {
    return signals;
  }

  for (let i = 1; i < candles.length; i++) {
    const signal = generateSignalForCandle(candles[i], candles[i - 1], trendStrength);
    if (signal) {
      signals.push(signal);
    }
  }

  return signals;
}

/**
 * 가장 최근 매매 신호 조회
 * @param candles 캔들 데이터 배열 (시간순 정렬)
 * @param trendStrength 추세 강도
 * @param lookbackPeriod 조회할 기간 (캔들 수)
 * @returns 가장 최근 매매 신호 또는 null
 */
export function getLatestSignal(
  candles: CandleWithIndicators[],
  trendStrength: number,
  lookbackPeriod: number = 10
): TradingSignal | null {
  if (candles.length < 2) {
    return null;
  }

  const startIdx = Math.max(1, candles.length - lookbackPeriod);
  
  for (let i = candles.length - 1; i >= startIdx; i--) {
    const signal = generateSignalForCandle(candles[i], candles[i - 1], trendStrength);
    if (signal) {
      return signal;
    }
  }

  return null;
}

/**
 * 신호 요약 정보 생성
 * @param signals 매매 신호 배열
 * @returns 요약 정보
 */
export function getSignalSummary(signals: TradingSignal[]): {
  totalSignals: number;
  buySignals: number;
  sellSignals: number;
  lastSignal: TradingSignal | null;
  bullishSignals: number;
  bearishSignals: number;
} {
  const buySignals = signals.filter(s => s.signal === 'BUY');
  const sellSignals = signals.filter(s => s.signal === 'SELL');
  const bullishSignals = signals.filter(s => s.isBullish);
  const bearishSignals = signals.filter(s => !s.isBullish);

  return {
    totalSignals: signals.length,
    buySignals: buySignals.length,
    sellSignals: sellSignals.length,
    lastSignal: signals.length > 0 ? signals[signals.length - 1] : null,
    bullishSignals: bullishSignals.length,
    bearishSignals: bearishSignals.length,
  };
}

/**
 * 전략 설정 인터페이스
 */
export interface TrendStochasticStrategyConfig {
  oversoldLevel: number;    // 과매도 레벨 (기본: 20)
  neutralLevel: number;     // 중립 레벨 (기본: 50)
  overboughtLevel: number;  // 과매수 레벨 (기본: 80)
  enableBullishAllLevels: boolean;  // 정배열 시 모든 레벨 활성화 (기본: true)
  enableBearishOnlyOverbought: boolean;  // 역배열 시 80 레벨만 활성화 (기본: true)
}

/**
 * 기본 전략 설정
 */
export const DEFAULT_STRATEGY_CONFIG: TrendStochasticStrategyConfig = {
  oversoldLevel: 20,
  neutralLevel: 50,
  overboughtLevel: 80,
  enableBullishAllLevels: true,
  enableBearishOnlyOverbought: true,
};

/**
 * 설정 가능한 전략 신호 생성
 * @param current 현재 캔들 데이터
 * @param previous 이전 캔들 데이터
 * @param trendStrength 추세 강도
 * @param config 전략 설정
 * @returns 매매 신호 또는 null
 */
export function generateSignalWithConfig(
  current: CandleWithIndicators,
  previous: CandleWithIndicators,
  trendStrength: number,
  config: TrendStochasticStrategyConfig = DEFAULT_STRATEGY_CONFIG
): TradingSignal | null {
  if (current.stochasticK === null || previous.stochasticK === null) {
    return null;
  }

  const currK = current.stochasticK;
  const prevK = previous.stochasticK;
  const isBullish = isBullishTrend(trendStrength);

  // 정배열인 경우
  if (isBullish && config.enableBullishAllLevels) {
    // 과매도 레벨 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, config.oversoldLevel)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: `정배열 + Stochastic ${config.oversoldLevel} 상향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: config.oversoldLevel,
        crossDirection: 'UP',
      };
    }

    // 중립 레벨 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, config.neutralLevel)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: `정배열 + Stochastic ${config.neutralLevel} 상향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: config.neutralLevel,
        crossDirection: 'UP',
      };
    }

    // 과매수 레벨 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, config.overboughtLevel)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: `정배열 + Stochastic ${config.overboughtLevel} 상향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: config.overboughtLevel,
        crossDirection: 'UP',
      };
    }

    // 과매도 레벨 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, config.oversoldLevel)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: `정배열 + Stochastic ${config.oversoldLevel} 하향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: config.oversoldLevel,
        crossDirection: 'DOWN',
      };
    }

    // 중립 레벨 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, config.neutralLevel)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: `정배열 + Stochastic ${config.neutralLevel} 하향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: config.neutralLevel,
        crossDirection: 'DOWN',
      };
    }

    // 과매수 레벨 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, config.overboughtLevel)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: `정배열 + Stochastic ${config.overboughtLevel} 하향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: true,
        crossLevel: config.overboughtLevel,
        crossDirection: 'DOWN',
      };
    }
  }
  // 역배열인 경우
  else if (isBearishTrend(trendStrength) && config.enableBearishOnlyOverbought) {
    // 과매수 레벨 상향 돌파 → 매수
    if (isCrossUp(prevK, currK, config.overboughtLevel)) {
      return {
        date: current.date,
        signal: 'BUY',
        reason: `역배열 + Stochastic ${config.overboughtLevel} 상향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: false,
        crossLevel: config.overboughtLevel,
        crossDirection: 'UP',
      };
    }

    // 과매수 레벨 하향 돌파 → 매도
    if (isCrossDown(prevK, currK, config.overboughtLevel)) {
      return {
        date: current.date,
        signal: 'SELL',
        reason: `역배열 + Stochastic ${config.overboughtLevel} 하향 돌파`,
        stochasticK: currK,
        stochasticD: current.stochasticD ?? 0,
        trendStrength,
        isBullish: false,
        crossLevel: config.overboughtLevel,
        crossDirection: 'DOWN',
      };
    }
  }

  return null;
}

// 사용 예시
/*
import { 
  generateSignals, 
  getLatestSignal, 
  getSignalSummary,
  CandleWithIndicators 
} from './trendStochasticStrategy';

// 캔들 데이터 예시
const candles: CandleWithIndicators[] = [
  { date: '2024-01-01', open: 100, high: 105, low: 98, close: 103, volume: 1000, stochasticK: 18, stochasticD: 15 },
  { date: '2024-01-02', open: 103, high: 110, low: 101, close: 108, volume: 1200, stochasticK: 22, stochasticD: 19 },
  // ...
];

// 추세 강도 (양수: 정배열, 음수: 역배열)
const trendStrength = 45.5; // 정배열

// 전체 신호 생성
const signals = generateSignals(candles, trendStrength);
console.log('전체 신호:', signals);

// 최근 신호 조회
const latestSignal = getLatestSignal(candles, trendStrength);
console.log('최근 신호:', latestSignal);

// 신호 요약
const summary = getSignalSummary(signals);
console.log('요약:', summary);
*/

