/**
 * Quant Engine v9 — Live Outcome Ledger
 * 실전 거래신호 추적 & CALIBRATED 전환 시스템
 * 생성: 2026-06-25
 */

// ────────────────────────────────────────────────────────────────────────────
// 설정
// ────────────────────────────────────────────────────────────────────────────

const LEDGER_SHEET_ID = "1N_A..."; // TODO: 스프레드시트 ID 입력
const LEDGER_SHEET_NAME = "live_outcome_ledger";

const LEDGER_HEADERS = [
  "signal_id",
  "date",
  "ticker",
  "signal_type",
  "signal_score",
  "entry_price",
  "entry_quantity",
  "entry_time",
  "style",
  "routing_confidence",
  "price_t5",
  "price_t10",
  "price_t20",
  "return_pct_t20",
  "outcome",
  "win_margin",
  "validation_status",
  "notes",
  "last_updated"
];

// ────────────────────────────────────────────────────────────────────────────
// 신호 기록
// ────────────────────────────────────────────────────────────────────────────

/**
 * addSignal_
 * 새로운 거래 신호를 레저에 추가
 *
 * @param {Object} signal - 신호 데이터
 * @return {string} signal_id
 */
function addSignal_(signal) {
  if (!signal.ticker || !signal.signal_type || !signal.entry_price) {
    throw new Error("필수 필드 누락: ticker, signal_type, entry_price");
  }

  const signalId = generateSignalId_(signal.date || new Date());
  const ss = SpreadsheetApp.openById(LEDGER_SHEET_ID);
  const sheet = ss.getSheetByName(LEDGER_SHEET_NAME);

  const row = [
    signalId,                          // signal_id
    signal.date || new Date(),         // date
    signal.ticker,                     // ticker
    signal.signal_type,                // signal_type (BUY|SELL)
    signal.signal_score || 0,          // signal_score
    signal.entry_price,                // entry_price
    signal.entry_quantity || 0,        // entry_quantity
    signal.entry_time || "00:00",      // entry_time
    signal.style || "UNCLASSIFIED",    // style
    signal.routing_confidence || 0,    // routing_confidence
    null,                              // price_t5 (T+5에 입력)
    null,                              // price_t10 (T+10에 입력)
    null,                              // price_t20 (T+20에 입력)
    null,                              // return_pct_t20 (자동 계산)
    "PENDING",                         // outcome
    null,                              // win_margin
    "UNVALIDATED",                     // validation_status
    signal.notes || "",                // notes
    new Date().toISOString()           // last_updated
  ];

  sheet.appendRow(row);
  Logger.log(`✓ 신호 기록: ${signalId} (${signal.ticker})`);

  return signalId;
}

/**
 * generateSignalId_
 * 고유한 signal_id 생성 (YYYYMMDD_HHMM_TICKER 형식)
 *
 * @param {Date} date
 * @return {string} signal_id
 */
function generateSignalId_(date) {
  const yyyy = date.getFullYear();
  const mm = String(date.getMonth() + 1).padStart(2, "0");
  const dd = String(date.getDate()).padStart(2, "0");
  const hh = String(date.getHours()).padStart(2, "0");
  const min = String(date.getMinutes()).padStart(2, "0");

  return `${yyyy}${mm}${dd}_${hh}${min}`;
}

// ────────────────────────────────────────────────────────────────────────────
// T+5, T+10, T+20 가격 입력
// ────────────────────────────────────────────────────────────────────────────

/**
 * updatePriceT5_
 * T+5 가격 입력 (자동 또는 수동)
 *
 * @param {string} signalId
 * @param {number} priceT5
 */
function updatePriceT5_(signalId, priceT5) {
  const ss = SpreadsheetApp.openById(LEDGER_SHEET_ID);
  const sheet = ss.getSheetByName(LEDGER_SHEET_NAME);

  const rowIndex = findSignalRow_(sheet, signalId);
  if (rowIndex === -1) throw new Error(`신호를 찾을 수 없음: ${signalId}`);

  sheet.getRange(rowIndex, 11).setValue(priceT5); // price_t5 = 11번째 열
  sheet.getRange(rowIndex, 19).setValue(new Date().toISOString()); // last_updated

  Logger.log(`✓ T+5 가격 입력: ${signalId} = ${priceT5}`);
}

/**
 * updatePriceT20_
 * T+20 가격 입력 + outcome 자동 계산
 *
 * @param {string} signalId
 * @param {number} priceT20
 */
function updatePriceT20_(signalId, priceT20) {
  const ss = SpreadsheetApp.openById(LEDGER_SHEET_ID);
  const sheet = ss.getSheetByName(LEDGER_SHEET_NAME);

  const rowIndex = findSignalRow_(sheet, signalId);
  if (rowIndex === -1) throw new Error(`신호를 찾을 수 없음: ${signalId}`);

  const range = sheet.getRange(rowIndex, 1, 1, LEDGER_HEADERS.length);
  const values = range.getValues()[0];

  // entry_price (인덱스 5) vs priceT20
  const entryPrice = values[5];
  const returnPctT20 = ((priceT20 - entryPrice) / entryPrice * 100).toFixed(2);

  // outcome 판정: WIN (-2% < ret < 2% = BREAKEVEN), LOSS, WIN
  let outcome = "BREAKEVEN";
  let winMargin = Math.abs(returnPctT20);

  if (returnPctT20 > 2) {
    outcome = "WIN";
  } else if (returnPctT20 < -2) {
    outcome = "LOSS";
    winMargin = returnPctT20;
  }

  // 업데이트
  sheet.getRange(rowIndex, 13).setValue(priceT20);          // price_t20
  sheet.getRange(rowIndex, 14).setValue(returnPctT20);      // return_pct_t20
  sheet.getRange(rowIndex, 15).setValue(outcome);           // outcome
  sheet.getRange(rowIndex, 16).setValue(winMargin);         // win_margin
  sheet.getRange(rowIndex, 17).setValue("PROVISIONAL");     // validation_status
  sheet.getRange(rowIndex, 19).setValue(new Date().toISOString()); // last_updated

  Logger.log(`✓ T+20 업데이트: ${signalId}, 수익률=${returnPctT20}%, outcome=${outcome}`);
}

// ────────────────────────────────────────────────────────────────────────────
// 통계 & 검증
// ────────────────────────────────────────────────────────────────────────────

/**
 * calculateStats_
 * 현재까지의 통계 계산 (win_rate, avg_win_margin, etc.)
 *
 * @return {Object} { total, completed, win_count, loss_count, win_rate, avg_margin }
 */
function calculateStats_() {
  const ss = SpreadsheetApp.openById(LEDGER_SHEET_ID);
  const sheet = ss.getSheetByName(LEDGER_SHEET_NAME);
  const data = sheet.getDataRange().getValues();

  let totalSignals = 0;
  let completedSignals = 0;
  let winCount = 0;
  let lossCount = 0;
  let totalWinMargin = 0;

  // 헤더 제외 (인덱스 1부터)
  for (let i = 1; i < data.length; i++) {
    const row = data[i];
    const validationStatus = row[16]; // validation_status
    const outcome = row[14];          // outcome
    const winMargin = row[15];        // win_margin

    totalSignals++;

    if (validationStatus === "PROVISIONAL" || validationStatus === "CALIBRATED") {
      completedSignals++;

      if (outcome === "WIN") {
        winCount++;
        totalWinMargin += Math.abs(winMargin);
      } else if (outcome === "LOSS") {
        lossCount++;
      }
    }
  }

  const winRate = completedSignals > 0 ? (winCount / completedSignals * 100) : 0;
  const avgMargin = completedSignals > 0 ? (totalWinMargin / winCount || 0) : 0;

  return {
    total: totalSignals,
    completed: completedSignals,
    win_count: winCount,
    loss_count: lossCount,
    breakeven_count: completedSignals - winCount - lossCount,
    win_rate: winRate.toFixed(2),
    avg_win_margin: avgMargin.toFixed(2),
    calibrated_progress: `${completedSignals}/30`
  };
}

/**
 * checkCalibrationReady_
 * CALIBRATED 전환 가능 여부 확인
 *
 * @return {Object} { ready, reason, stats }
 */
function checkCalibrationReady_() {
  const stats = calculateStats_();

  const minSamples = 30;
  const minWinRate = 60;

  const ready = (stats.completed >= minSamples && parseFloat(stats.win_rate) >= minWinRate);
  const reason = !ready ?
    `샘플: ${stats.completed}/${minSamples}, 승률: ${stats.win_rate}%/${minWinRate}%` :
    "✅ CALIBRATED 전환 조건 충족!";

  return {
    ready: ready,
    reason: reason,
    stats: stats
  };
}

/**
 * calibrateIfReady_
 * CALIBRATED 전환 (자동 또는 수동)
 */
function calibrateIfReady_() {
  const check = checkCalibrationReady_();

  if (!check.ready) {
    Logger.log(`⏳ CALIBRATED 전환 대기: ${check.reason}`);
    return;
  }

  // 모든 PROVISIONAL을 CALIBRATED로 전환
  const ss = SpreadsheetApp.openById(LEDGER_SHEET_ID);
  const sheet = ss.getSheetByName(LEDGER_SHEET_NAME);
  const data = sheet.getDataRange().getValues();

  let calibratedCount = 0;

  for (let i = 1; i < data.length; i++) {
    if (data[i][16] === "PROVISIONAL") {
      sheet.getRange(i + 1, 17).setValue("CALIBRATED");
      calibratedCount++;
    }
  }

  Logger.log(`✅ CALIBRATED 전환 완료: ${calibratedCount}개 신호`);
  Logger.log(`📊 최종 통계: ${JSON.stringify(check.stats, null, 2)}`);
}

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

/**
 * findSignalRow_
 * signal_id로 행 번호 찾기
 *
 * @param {Sheet} sheet
 * @param {string} signalId
 * @return {number} 행 번호 (없으면 -1)
 */
function findSignalRow_(sheet, signalId) {
  const data = sheet.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === signalId) {
      return i + 1; // 1-indexed
    }
  }

  return -1;
}

/**
 * initializeLedger_
 * 레저 시트 초기화 (첫 실행 시만)
 */
function initializeLedger_() {
  const ss = SpreadsheetApp.openById(LEDGER_SHEET_ID);
  let sheet = ss.getSheetByName(LEDGER_SHEET_NAME);

  if (!sheet) {
    sheet = ss.insertSheet(LEDGER_SHEET_NAME);
  }

  // 헤더 설정
  sheet.getRange(1, 1, 1, LEDGER_HEADERS.length).setValues([LEDGER_HEADERS]);

  // 포맷팅
  sheet.getRange(1, 1, 1, LEDGER_HEADERS.length)
    .setBackground("#1f77b4")
    .setFontColor("white")
    .setFontWeight("bold");

  Logger.log(`✓ 레저 시트 초기화 완료: ${LEDGER_SHEET_NAME}`);
}

/**
 * 테스트 함수
 */
function testLiveOutcomeLedger() {
  Logger.log("=== Live Outcome Ledger 테스트 ===");

  // 테스트 신호 추가
  const testSignal = {
    date: new Date(),
    ticker: "000660",
    signal_type: "BUY",
    signal_score: 75,
    entry_price: 100000,
    entry_quantity: 10,
    style: "SWING",
    routing_confidence: 80,
    notes: "테스트 신호"
  };

  try {
    // 초기화
    initializeLedger_();

    // 신호 추가
    // const signalId = addSignal_(testSignal);
    // Logger.log(`신호 ID: ${signalId}`);

    // 통계 확인
    const stats = calculateStats_();
    Logger.log(`통계: ${JSON.stringify(stats, null, 2)}`);

    // CALIBRATED 준비 여부
    const check = checkCalibrationReady_();
    Logger.log(`CALIBRATED 준비: ${JSON.stringify(check, null, 2)}`);
  } catch (error) {
    Logger.log(`❌ 오류: ${error.message}`);
  }
}
