/**
 * Download 1-minute klines from BitMEX REST API for XBTUSD (inverse perp).
 * Same period as our Bybit data: Apr 2025 → Apr 2026.
 *
 * BitMEX API: GET /api/v1/trade/bucketed?binSize=1m&symbol=XBTUSD
 * Returns: timestamp, open, high, low, close, volume, turnover, etc.
 * No auth needed. Rate limit ~1 req/sec, 1000 candles per request.
 */
import fs from 'node:fs'
import https from 'node:https'

const SYMBOL   = 'XBTUSD'
const OUT_DIR  = 'data/klines'
const OUT_FILE = `${OUT_DIR}/XBTUSD-1m.jsonl`

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', 'Accept': 'application/json' } }, res => {
      let d = ''
      res.on('data', c => d += c)
      res.on('end', () => {
        try { resolve(JSON.parse(d)) }
        catch (e) { reject(new Error(`Parse error: ${d.slice(0, 200)}`)) }
      })
      res.on('error', reject)
    }).on('error', reject)
  })
}

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

  const startTime = new Date(START_DATE + 'T00:00:00.000Z')
  const endTime = new Date(END_DATE + 'T00:00:00.000Z')

  process.stderr.write(`Downloading ${SYMBOL} 1m klines: ${START_DATE} → ${END_DATE}\n`)
  process.stderr.write(`Endpoint: BitMEX /api/v1/trade/bucketed\n\n`)

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

  while (cursor < endTime) {
    const startISO = cursor.toISOString()
    const url = `https://www.bitmex.com/api/v1/trade/bucketed?binSize=1m&partial=false&symbol=${SYMBOL}&count=1000&start=0&startTime=${encodeURIComponent(startISO)}`

    try {
      const data = await get(url)

      if (!Array.isArray(data)) {
        if (data?.error) {
          process.stderr.write(`  API error: ${JSON.stringify(data.error)}\n`)
          // Rate limited — wait and retry
          await new Promise(r => setTimeout(r, 5000))
          continue
        }
        process.stderr.write(`  Unexpected response: ${JSON.stringify(data).slice(0, 200)}\n`)
        cursor = new Date(cursor.getTime() + 1000 * 60000)
        continue
      }

      if (data.length === 0) {
        // No more data in this range — advance cursor
        cursor = new Date(cursor.getTime() + 1000 * 60000)
        requests++
        continue
      }

      for (const candle of data) {
        const ts = new Date(candle.timestamp).getTime()
        if (ts >= endTime.getTime()) continue
        if (candle.open == null || candle.close == null) continue

        fs.writeSync(fd, JSON.stringify({
          ts,
          o: candle.open,
          h: candle.high,
          l: candle.low,
          c: candle.close,
          v: candle.volume,          // contracts
          usd: candle.turnover ? candle.turnover / 1e8 : candle.volume  // turnover is in satoshi for inverse
        }) + '\n')
        total++
      }

      // Advance cursor past the last candle
      const lastTs = new Date(data[data.length - 1].timestamp).getTime()
      cursor = new Date(lastTs + 60000)

    } catch (e: any) {
      process.stderr.write(`  Error at ${cursor.toISOString()}: ${e.message}\n`)
      await new Promise(r => setTimeout(r, 3000))
      cursor = new Date(cursor.getTime() + 100 * 60000)
    }

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

    // Rate limit: BitMEX allows ~1 req/sec unauthenticated
    await new Promise(r => setTimeout(r, 1200))
  }

  fs.closeSync(fd)

  process.stderr.write(`\nDone: ${total} candles → ${OUT_FILE}\n`)
  process.stderr.write(`Size: ${(fs.statSync(OUT_FILE).size / 1e6).toFixed(1)} MB\n`)

  // Verify
  const lines = fs.readFileSync(OUT_FILE, 'utf8').trim().split('\n')
  const first = JSON.parse(lines[0])
  const last = JSON.parse(lines[lines.length - 1])
  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} → $${last.c}\n`)
}

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