/**
 * Download 1-minute klines from Bybit REST API for a full year.
 * ~525,600 candles, stored as compact JSONL.
 *
 * 1-min bars are sufficient for the momentum strategy:
 *   lookback=60 bars (60min), hold=30 bars (30min), threshold=5bps.
 */
import fs from 'node:fs'
import https from 'node:https'

const SYMBOL   = 'BTCUSDT'
const CATEGORY = 'linear'
const INTERVAL = '1'           // 1-minute klines
const OUT_DIR  = 'data/klines'
const OUT_FILE = `${OUT_DIR}/${SYMBOL}-1m.jsonl`

// Full year: Apr 10 2025 → Apr 10 2026
const START_DATE = '2025-04-10'
const END_DATE   = '2026-04-10'

function get(url: string): Promise<any> {
  return new Promise((resolve, reject) => {
    https.get(url, { headers: { 'User-Agent': 'txocap/1.0' } }, res => {
      let d = ''
      res.on('data', c => d += c)
      res.on('end', () => { try { resolve(JSON.parse(d)) } catch (e) { reject(e) } })
      res.on('error', reject)
    }).on('error', reject)
  })
}

async function main() {
  fs.mkdirSync(OUT_DIR, { recursive: true })

  const startMs = new Date(START_DATE + 'T00:00:00Z').getTime()
  const endMs   = new Date(END_DATE + 'T00:00:00Z').getTime()
  const totalMinutes = (endMs - startMs) / 60000
  
  process.stderr.write(`Downloading ${SYMBOL} 1m klines: ${START_DATE} → ${END_DATE}\n`)
  process.stderr.write(`Expected: ~${Math.round(totalMinutes)} candles in ~${Math.ceil(totalMinutes / 1000)} requests\n\n`)

  const fd = fs.openSync(OUT_FILE, 'w')
  let cursor = startMs
  let total = 0
  let requests = 0

  while (cursor < endMs) {
    const batchEnd = Math.min(cursor + 1000 * 60000, endMs)
    const url = `https://api.bybit.com/v5/market/kline?category=${CATEGORY}&symbol=${SYMBOL}&interval=${INTERVAL}&start=${cursor}&end=${batchEnd}&limit=1000`

    try {
      const data = await get(url)
      const list = data.result?.list
      if (!list || list.length === 0) {
        // No data for this range — skip forward
        cursor = batchEnd
        requests++
        continue
      }

      // Bybit returns newest first — reverse to chronological
      const candles = list.reverse()
      for (const c of candles) {
        const ts = Number(c[0])
        if (ts < cursor || ts >= endMs) continue
        // [startTime, open, high, low, close, volume, turnover]
        fs.writeSync(fd, JSON.stringify({
          ts, o: Number(c[1]), h: Number(c[2]), l: Number(c[3]), c: Number(c[4]),
          v: Number(c[5]), usd: Number(c[6])
        }) + '\n')
        total++
      }

      // Advance cursor past the last candle we received
      const lastTs = Number(candles[candles.length - 1][0])
      cursor = lastTs + 60000  // next minute after last candle
    } catch (e: any) {
      process.stderr.write(`  Error at ${new Date(cursor).toISOString()}: ${e.message}\n`)
      cursor += 60000 * 100  // skip forward on error
    }

    requests++
    if (requests % 50 === 0) {
      const pct = ((cursor - startMs) / (endMs - startMs) * 100).toFixed(1)
      process.stderr.write(`  ${pct}% — ${total} candles, ${requests} requests, at ${new Date(cursor).toISOString().slice(0,10)}\n`)
    }

    // Rate limit: 100ms between requests
    await new Promise(r => setTimeout(r, 100))
  }

  fs.closeSync(fd)

  process.stderr.write(`\nDone: ${total} candles written to ${OUT_FILE}\n`)
  process.stderr.write(`File size: ${(fs.statSync(OUT_FILE).size / 1e6).toFixed(1)} MB\n`)
  
  // Verify: read first and last line
  const firstLine = fs.readFileSync(OUT_FILE, 'utf8').split('\n')[0]
  const lines = fs.readFileSync(OUT_FILE, 'utf8').trim().split('\n')
  const lastLine = lines[lines.length - 1]
  const first = JSON.parse(firstLine)
  const last = JSON.parse(lastLine)
  process.stderr.write(`Range: ${new Date(first.ts).toISOString().slice(0,10)} → ${new Date(last.ts).toISOString().slice(0,10)}\n`)
  process.stderr.write(`Price: $${first.o.toFixed(0)} → $${last.c.toFixed(0)}\n`)
}

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