import { createWriteStream, mkdirSync } from 'node:fs'
import type { WriteStream } from 'node:fs'
import type { TapeTrade } from '../core/types.js'
import type { OrderbookState } from './orderbook.js'

export interface RecordedTrade {
  type: 'trade'
  ts: number
  data: TapeTrade
}

export interface RecordedOrderbook {
  type: 'orderbook'
  ts: number
  data: {
    bestBid: number | null
    bestAsk: number | null
    midPrice: number | null
    spreadBps: number | null
    bidsDepth5: [number, number][]
    asksDepth5: [number, number][]
  }
}

export type RecordedEvent = RecordedTrade | RecordedOrderbook

export class TapeRecorder {
  private tradeStream: WriteStream
  private obStream: WriteStream
  private tradeCount = 0
  private obCount = 0
  private lastObWrite = 0
  private readonly obIntervalMs: number

  constructor(dir: string, obIntervalMs = 250) {
    mkdirSync(dir, { recursive: true })
    this.tradeStream = createWriteStream(`${dir}/trades.jsonl`, { flags: 'a' })
    this.obStream = createWriteStream(`${dir}/orderbook.jsonl`, { flags: 'a' })
    this.obIntervalMs = obIntervalMs
  }

  recordTrade(trade: TapeTrade): void {
    const event: RecordedTrade = {
      type: 'trade',
      ts: trade.timestamp,
      data: {
        exchange: trade.exchange,
        exchangeClass: trade.exchangeClass,
        instrumentType: trade.instrumentType,
        symbol: trade.symbol,
        timestamp: trade.timestamp,
        price: trade.price,
        size: trade.size,
        notionalUsd: trade.notionalUsd,
        side: trade.side,
        tradeId: trade.tradeId
      }
    }
    this.tradeStream.write(JSON.stringify(event) + '\n')
    this.tradeCount++
  }

  recordOrderbook(state: OrderbookState): void {
    const now = Date.now()
    if (now - this.lastObWrite < this.obIntervalMs) return
    this.lastObWrite = now

    const event: RecordedOrderbook = {
      type: 'orderbook',
      ts: state.updatedAt,
      data: {
        bestBid: state.bestBid,
        bestAsk: state.bestAsk,
        midPrice: state.midPrice,
        spreadBps: state.spreadBps,
        bidsDepth5: state.bids.slice(0, 5).map(l => [l.price, l.size] as [number, number]),
        asksDepth5: state.asks.slice(0, 5).map(l => [l.price, l.size] as [number, number])
      }
    }
    this.obStream.write(JSON.stringify(event) + '\n')
    this.obCount++
  }

  close(): { trades: number; orderbooks: number } {
    this.tradeStream.end()
    this.obStream.end()
    return { trades: this.tradeCount, orderbooks: this.obCount }
  }
}
