/**
 * Momentum strategy: full backtest on all historical + live sessions.
 * Uses MomentumEngine from src/core/momentum.ts.
 */
import fs from 'node:fs'
import { loadSession } from '../runners/replay.js'
import { MomentumEngine, DEFAULT_CONFIG, replayMomentum } from '../core/momentum.js'
import type { MomentumConfig, MomentumState } from '../core/momentum.js'

const HIST_DIR = 'data/historical'
const LIVE_DIR = 'data/sessions'

function printState(name: string, st: MomentumState) {
  const wins = st.closed.filter(t => t.netUsd > 0)
  const losses = st.closed.filter(t => t.netUsd <= 0)
  const wr = st.closed.length > 0 ? (wins.length / st.closed.length * 100).toFixed(0) : '0'
  const avgWin = wins.length > 0 ? (wins.reduce((s, t) => s + t.netUsd, 0) / wins.length).toFixed(2) : '0'
  const avgLoss = losses.length > 0 ? (losses.reduce((s, t) => s + t.netUsd, 0) / losses.length).toFixed(2) : '0'
  const stops = st.closed.filter(t => t.exitReason === 'stop').length
  const times = st.closed.filter(t => t.exitReason === 'time').length
  const avgHold = st.closed.length > 0 ? (st.closed.reduce((s, t) => s + t.holdBars, 0) / st.closed.length * 10 / 60).toFixed(0) : '0'
  const pnl = st.equity - DEFAULT_CONFIG.startingCapital

  console.log(`  ${name.padEnd(25)} $${DEFAULT_CONFIG.startingCapital}→$${st.equity.toFixed(2)} (${pnl >= 0 ? '+' : ''}$${pnl.toFixed(2)}) trades=${st.closed.length} WR=${wr}% avgW=$${avgWin} avgL=$${avgLoss} DD=${st.maxDdPct}% fees=$${st.totalFees.toFixed(2)} exits:T${times}/S${stops} hold=${avgHold}min`)
}

function printTrades(st: MomentumState) {
  for (const t of st.closed) {
    const dir = t.side === 'long' ? '▲L' : '▼S'
    console.log(`    ${dir} ${t.entryPrice.toFixed(1)}→${t.exitPrice.toFixed(1)} ${t.sizeBtc}btc gross=${t.grossBps.toFixed(1)}bps net=${t.netBps.toFixed(1)}bps $${t.netUsd.toFixed(2)} ${t.exitReason.toUpperCase()} ${(t.holdBars*10/60).toFixed(0)}min`)
  }
}

async function main() {
  console.log(`${'═'.repeat(90)}`)
  console.log('MOMENTUM STRATEGY BACKTEST')
  console.log(`${'═'.repeat(90)}`)
  console.log()
  console.log(`Config: lb=${DEFAULT_CONFIG.lookbackBars/6}min hold=${DEFAULT_CONFIG.holdBars/6}min thresh=${DEFAULT_CONFIG.entryThreshBps}bps stop=${DEFAULT_CONFIG.stopBps}bps fee=${DEFAULT_CONFIG.entryFeeBps}bps/side`)
  console.log(`Capital: $${DEFAULT_CONFIG.startingCapital} @ ${DEFAULT_CONFIG.leverage}x leverage, ${(DEFAULT_CONFIG.riskPct*100).toFixed(0)}% risk/trade`)
  console.log()

  // Load historical sessions
  const histDates = fs.existsSync(HIST_DIR)
    ? fs.readdirSync(HIST_DIR).filter(d => {
        try { return fs.statSync(`${HIST_DIR}/${d}/trades.jsonl`).size > 100_000 } catch { return false }
      }).sort()
    : []

  // Load live sessions
  const liveDirs = fs.existsSync(LIVE_DIR)
    ? fs.readdirSync(LIVE_DIR).filter(d => {
        try { return fs.statSync(`${LIVE_DIR}/${d}/trades.jsonl`).size > 1000 } catch { return false }
      }).sort()
    : []

  let totalPnl = 0, totalTrades = 0, totalWins = 0, worstDdPct = 0, totalFees = 0
  let runningEquity = DEFAULT_CONFIG.startingCapital

  // Run on historical data
  if (histDates.length > 0) {
    console.log('── HISTORICAL SESSIONS ──')
    for (const date of histDates) {
      process.stderr.write(`Loading ${date}...`)
      const { bars } = await loadSession(`${HIST_DIR}/${date}`)
      process.stderr.write(` ${bars.length} bars\n`)
      if (bars.length < 500) continue

      const barsData = bars.map(([, b]) => b)

      // Run with compounding equity
      const config = { ...DEFAULT_CONFIG, startingCapital: runningEquity }
      const st = replayMomentum(barsData, config)
      const pnl = st.equity - runningEquity

      printState(date, { ...st, equity: st.equity, maxDdPct: st.maxDdPct })

      totalPnl += pnl
      totalTrades += st.closed.length
      totalWins += st.closed.filter(t => t.netUsd > 0).length
      if (st.maxDdPct > worstDdPct) worstDdPct = st.maxDdPct
      totalFees += st.totalFees
      runningEquity = st.equity
    }
  }

  // Run on live sessions
  if (liveDirs.length > 0) {
    console.log('\n── LIVE-RECORDED SESSIONS ──')
    for (const dir of liveDirs) {
      const fullDir = `${LIVE_DIR}/${dir}`
      process.stderr.write(`Loading ${dir}...`)
      const { bars } = await loadSession(fullDir)
      process.stderr.write(` ${bars.length} bars\n`)
      if (bars.length < 500) continue

      const barsData = bars.map(([, b]) => b)
      const config = { ...DEFAULT_CONFIG, startingCapital: runningEquity }
      const st = replayMomentum(barsData, config)
      const pnl = st.equity - runningEquity

      printState(dir, { ...st })

      totalPnl += pnl
      totalTrades += st.closed.length
      totalWins += st.closed.filter(t => t.netUsd > 0).length
      if (st.maxDdPct > worstDdPct) worstDdPct = st.maxDdPct
      totalFees += st.totalFees
      runningEquity = st.equity
    }
  }

  // Aggregate
  console.log(`\n${'═'.repeat(90)}`)
  console.log('AGGREGATE')
  const wr = totalTrades > 0 ? (totalWins / totalTrades * 100).toFixed(0) : '0'
  const retPct = ((runningEquity - DEFAULT_CONFIG.startingCapital) / DEFAULT_CONFIG.startingCapital * 100).toFixed(1)
  console.log(`  $${DEFAULT_CONFIG.startingCapital} → $${runningEquity.toFixed(2)} (${retPct}%)`)
  console.log(`  trades=${totalTrades} wins=${totalWins} WR=${wr}%`)
  console.log(`  worst session DD=${worstDdPct.toFixed(2)}%`)
  console.log(`  total fees=$${totalFees.toFixed(2)}`)
  console.log(`${'═'.repeat(90)}`)

  // Show detailed trade log for a couple of sessions
  if (histDates.length > 0) {
    console.log('\n── TRADE LOG: Best and Worst Historical Sessions ──')
    const sessionResults: { date: string; pnl: number; st: MomentumState }[] = []
    for (const date of histDates) {
      const { bars } = await loadSession(`${HIST_DIR}/${date}`)
      if (bars.length < 500) continue
      const barsData = bars.map(([, b]) => b)
      const st = replayMomentum(barsData, DEFAULT_CONFIG)
      sessionResults.push({ date, pnl: st.equity - DEFAULT_CONFIG.startingCapital, st })
    }
    sessionResults.sort((a, b) => b.pnl - a.pnl)
    for (const r of [sessionResults[0], sessionResults[sessionResults.length - 1]]) {
      console.log(`\n  ${r.date} (${r.pnl >= 0 ? '+' : ''}$${r.pnl.toFixed(2)}):`)
      printTrades(r.st)
    }
  }
}

main().catch(e => { process.stderr.write(`FATAL: ${e instanceof Error ? e.stack : e}\n`); process.exit(1) })
