/**
 * Quant Engine v9 Hardening — GAS Data Feed & Calculation Layer
 * 생성: 2026-06-25
 * 목적: P3~P6 공식 구현, 실시간 계산, 스프레드시트 연동
 */

// ────────────────────────────────────────────────────────────────────────────
// P3: 손절 체계 (3개 함수)
// ────────────────────────────────────────────────────────────────────────────

/**
 * calcAbsoluteRiskStopV1_
 * P3: 절대 손실 금지선
 *
 * @param {number} entryPrice - 진입가 (KRW)
 * @param {number} atr20 - 20일 ATR (KRW)
 * @return {number} 손절 가격
 */
function calcAbsoluteRiskStopV1_(entryPrice, atr20) {
  if (!entryPrice || !atr20) return null;

  // max(entry * 0.92, entry - ATR20 * 1.5)
  const percentStop = entryPrice * 0.92;
  const atrStop = entryPrice - (atr20 * 1.5);

  return Math.max(percentStop, atrStop);
}

/**
 * calcRelativeUnderperfAlertV1_
 * P3: 상대 성과 추적 → WATCH/TRIM_30/TRIM_50/EXIT_100 상태 결정
 *
 * @param {number} retStock20d - 개별주 20일 수익률 (%)
 * @param {number} retMarket20d - 시장 20일 수익률 (%)
 * @return {string} alert_state
 */
function calcRelativeUnderperfAlertV1_(retStock20d, retMarket20d) {
  if (typeof retStock20d !== 'number' || typeof retMarket20d !== 'number') {
    return 'UNKNOWN';
  }

  const excessReturn = retStock20d - retMarket20d;

  if (excessReturn > -10) {
    return 'WATCH'; // -10% 이상: 정상 추적
  } else if (excessReturn >= -15) {
    return 'TRIM_30'; // -10%~-15%: 30% 감소
  } else if (excessReturn >= -20) {
    return 'TRIM_50'; // -15%~-20%: 50% 감소
  } else if (excessReturn < -20) {
    return 'EXIT_100'; // -20% 초과: 전량 청산 (절대손실 확인 필수)
  }

  return 'WATCH';
}

/**
 * calcStopActionLadderV1_
 * P3: 상대 성과 신호 + 절대손실을 종합하여 최종 액션 결정
 *
 * @param {string} alertState - WATCH|TRIM_30|TRIM_50|EXIT_100
 * @param {number} underperfPct - 상대 underperf 퍼센트
 * @param {number} absoluteLossPct - 절대손실 퍼센트
 * @return {string} 최종 액션
 */
function calcStopActionLadderV1_(alertState, underperfPct, absoluteLossPct) {
  // 상대 성과만으로 EXIT_100 불가: 절대손실 >= 8% 필요
  if (alertState === 'EXIT_100' && absoluteLossPct < 8) {
    return 'TRIM_50'; // 격하
  }

  return alertState; // WATCH|TRIM_30|TRIM_50|EXIT_100
}

// ────────────────────────────────────────────────────────────────────────────
// P4: 라우팅 단일화 (1개 함수)
// ────────────────────────────────────────────────────────────────────────────

/**
 * buildRoutePacket_
 * P4: SCALP/SWING/MOMENTUM/POSITION 4가지 스타일 점수 + best_style 결정
 *
 * @param {string} ticker - 종목코드
 * @param {number} technicalScore - 기술지표 점수 (0-100)
 * @param {number} smartMoneyScore - 스마트머니 점수 (0-100)
 * @param {number} liquidityScore - 유동성 점수 (0-100)
 * @param {number} fundamentalScore - 펀더멘탈 점수 (0-100)
 * @return {Object} { scalp, swing, momentum, position, best_style, recommended_pct, blocked_reasons }
 */
function buildRoutePacket_(ticker, technicalScore, smartMoneyScore, liquidityScore, fundamentalScore) {
  if (!ticker) return null;

  // 스타일별 가중치
  const weights = {
    SCALP: { technical: 0.50, smart_money: 0.25, liquidity: 0.15, fundamental: 0.10 },
    SWING: { smart_money: 0.35, technical: 0.30, liquidity: 0.20, fundamental: 0.15 },
    MOMENTUM: { fundamental: 0.40, smart_money: 0.30, technical: 0.20, liquidity: 0.10 },
    POSITION: { fundamental: 0.55, smart_money: 0.20, liquidity: 0.15, technical: 0.10 }
  };

  // 각 스타일 점수 계산
  const scalpScore = (technicalScore * weights.SCALP.technical +
                      smartMoneyScore * weights.SCALP.smart_money +
                      liquidityScore * weights.SCALP.liquidity +
                      fundamentalScore * weights.SCALP.fundamental);

  const swingScore = (smartMoneyScore * weights.SWING.smart_money +
                      technicalScore * weights.SWING.technical +
                      liquidityScore * weights.SWING.liquidity +
                      fundamentalScore * weights.SWING.fundamental);

  const momentumScore = (fundamentalScore * weights.MOMENTUM.fundamental +
                         smartMoneyScore * weights.MOMENTUM.smart_money +
                         technicalScore * weights.MOMENTUM.technical +
                         liquidityScore * weights.MOMENTUM.liquidity);

  const positionScore = (fundamentalScore * weights.POSITION.fundamental +
                         smartMoneyScore * weights.POSITION.smart_money +
                         liquidityScore * weights.POSITION.liquidity +
                         technicalScore * weights.POSITION.technical);

  // best_style 결정
  const scores = {
    SCALP: scalpScore,
    SWING: swingScore,
    MOMENTUM: momentumScore,
    POSITION: positionScore
  };

  const bestStyle = Object.keys(scores).reduce((a, b) => scores[a] > scores[b] ? a : b);
  const bestScore = scores[bestStyle];

  // conviction_to_pct 매핑
  let recommendedPct = 0;
  if (bestScore >= 80) recommendedPct = 7.0;
  else if (bestScore >= 65) recommendedPct = 5.0;
  else if (bestScore >= 50) recommendedPct = 3.0;
  else if (bestScore >= 35) recommendedPct = 1.5;
  else recommendedPct = 0; // 진입금지

  return {
    ticker: ticker,
    scalp: scalpScore.toFixed(2),
    swing: swingScore.toFixed(2),
    momentum: momentumScore.toFixed(2),
    position: positionScore.toFixed(2),
    best_style: bestStyle,
    conviction_score: bestScore.toFixed(2),
    recommended_pct: recommendedPct,
    timestamp: new Date().toISOString()
  };
}

// ────────────────────────────────────────────────────────────────────────────
// P5: 뒷북 차단 (2개 함수)
// ────────────────────────────────────────────────────────────────────────────

/**
 * calcAlphaLeadV1_
 * P5: Alpha Lead Entry Gate — alpha_lead_score >= 75 → PILOT_ALLOWED
 *
 * @param {number} alphaLeadScore - 알파 리드 점수 (0-100)
 * @param {string} leadEntryState - PILOT_ALLOWED|BLOCKED
 * @param {number} pilotPnL - 파일럿 PnL (%)
 * @param {boolean} flowConfirmed - 유입 확인 여부
 * @return {Object} { allowed, alpha_lead_score, entry_tranche, reason }
 */
function calcAlphaLeadV1_(alphaLeadScore, leadEntryState, pilotPnL, flowConfirmed) {
  if (typeof alphaLeadScore !== 'number') return null;

  const allowed = alphaLeadScore >= 75 && leadEntryState === 'PILOT_ALLOWED';

  return {
    alpha_lead_score: alphaLeadScore,
    pilot_allowed: allowed,
    pilot_pnl_check: pilotPnL >= 0,
    flow_confirmed: flowConfirmed,
    entry_tranche: allowed ? 'T1_30' : null, // T1: 30%, T2: 30%, T3: 40%
    reason: allowed ? 'ALPHA_LEAD_GATE_PASSED' : 'ALPHA_LEAD_GATE_BLOCKED'
  };
}

/**
 * calcDistributionRiskV1_
 * P5: Pre-Distribution Early Warning — distribution_risk >= 70 → BLOCK_BUY
 *
 * @param {number} distributionRiskScore - 배분 위험 점수 (0-100)
 * @param {boolean} priceUpVolDown - 가격상승 & 거래량 하락
 * @param {boolean} foreignInstNetSell5d - 외국인 순매도 (5일)
 * @param {boolean} candleUpperTailCluster - 상부 꼬리 형성
 * @return {Object} { blocked, distribution_risk_score, reasons }
 */
function calcDistributionRiskV1_(distributionRiskScore, priceUpVolDown, foreignInstNetSell5d, candleUpperTailCluster) {
  if (typeof distributionRiskScore !== 'number') return null;

  const reasons = [];

  if (distributionRiskScore >= 70) reasons.push('HIGH_DISTRIBUTION_RISK');
  if (priceUpVolDown) reasons.push('PRICE_UP_VOL_DOWN');
  if (foreignInstNetSell5d) reasons.push('FOREIGN_INST_NET_SELL');
  if (candleUpperTailCluster) reasons.push('UPPER_TAIL_CLUSTER');

  const blocked = reasons.length > 0;

  return {
    distribution_risk_score: distributionRiskScore,
    buy_allowed: !blocked,
    block_reasons: reasons,
    action: blocked ? 'BLOCK_BUY' : 'BUY_ALLOWED'
  };
}

// ────────────────────────────────────────────────────────────────────────────
// P6: 현금확보 (1개 함수)
// ────────────────────────────────────────────────────────────────────────────

/**
 * calcCashRecoveryOptimizerV1_
 * P6: K2 50/50 분할 매도 + value_damage <= 10% 유지
 *
 * @param {number} currentAssetKRW - 현재 자산 (KRW)
 * @param {number} shortfallKRW - 현금 부족액 (KRW)
 * @param {number} atr20 - 20일 ATR (KRW)
 * @param {number} prevClose - 전일 종가 (KRW)
 * @return {Object} { immediate_qty_pct, rebound_wait_qty_pct, rebound_trigger_price, value_damage_max_pct }
 */
function calcCashRecoveryOptimizerV1_(currentAssetKRW, shortfallKRW, atr20, prevClose) {
  if (!currentAssetKRW || !shortfallKRW || !atr20 || !prevClose) return null;

  // K2 50/50 분할
  const immediateQtyPct = 50; // 즉시 50%
  const reboundWaitQtyPct = 50; // 반등 대기 50%

  // rebound_trigger_price = prevClose + 0.5 * ATR20
  const reboundTriggerPrice = prevClose + (atr20 * 0.5);

  // value_damage_raw_pct: 매도액 / 포트폴리오 가치 * 100
  // 상한: 10%
  const valueDamageMaxPct = 10;
  const sellAmountTarget = shortfallKRW / valueDamageMaxPct * 100; // 역산

  return {
    strategy: 'K2_50_50_SPLIT',
    immediate_qty_pct: immediateQtyPct,
    rebound_wait_qty_pct: reboundWaitQtyPct,
    rebound_trigger_price: reboundTriggerPrice.toFixed(0),
    value_damage_max_pct: valueDamageMaxPct,
    expected_recovery_krw: (currentAssetKRW * 0.05).toFixed(0), // 보수 추정: 5% 회수
    timestamp: new Date().toISOString()
  };
}

// ────────────────────────────────────────────────────────────────────────────
// 유틸리티
// ────────────────────────────────────────────────────────────────────────────

/**
 * 테스트 함수 (배포 후 삭제)
 */
function testP3Functions() {
  Logger.log('=== P3 Functions Test ===');

  // Test calcAbsoluteRiskStopV1_
  const stopPrice = calcAbsoluteRiskStopV1_(100000, 2000);
  Logger.log('Stop Price: ' + stopPrice);

  // Test calcRelativeUnderperfAlertV1_
  const alertState = calcRelativeUnderperfAlertV1_(-5, 10);
  Logger.log('Alert State: ' + alertState);

  // Test buildRoutePacket_
  const route = buildRoutePacket_('000660', 75, 65, 70, 60);
  Logger.log('Route Packet: ' + JSON.stringify(route, null, 2));

  // Test P5
  const alphaLead = calcAlphaLeadV1_(80, 'PILOT_ALLOWED', 5, true);
  Logger.log('Alpha Lead: ' + JSON.stringify(alphaLead, null, 2));

  // Test P6
  const cashRecovery = calcCashRecoveryOptimizerV1_(394191813, 41342219, 2500, 50000);
  Logger.log('Cash Recovery: ' + JSON.stringify(cashRecovery, null, 2));
}
