const WebSocket = require("ws");

class MarketDataService {
  constructor() {
    this.tickers = new Map();   // latest live prices
    this.candles1m = new Map(); // in-memory current 1m candle per symbol
    this.ws = null;
    this.reconnectTimer = null;
  }

  normalizeSymbol(localSymbol) {
    return String(localSymbol || "").replaceAll("_", "").toUpperCase();
  }

  start(symbols = []) {
    const streamSymbols = [...new Set(symbols)]
      .map((s) => this.normalizeSymbol(s))
      .filter(Boolean)
      .map((s) => `${s.toLowerCase()}@miniTicker`);

    if (!streamSymbols.length) {
      console.log("No symbols to stream");
      return;
    }

    const url = `wss://stream.binance.com:9443/stream?streams=${streamSymbols.join("/")}`;
    this.ws = new WebSocket(url);

    this.ws.on("open", () => {
      console.log("Binance WS connected");
    });

    this.ws.on("message", (raw) => {
      try {
        const msg = JSON.parse(raw.toString());
        const d = msg?.data;
        if (!d?.s) return;

        // miniTicker fields from Binance:
        // s symbol, c close, o open, h high, l low, v volume, q quote volume
        const ticker = {
          symbol: d.s,
          price: Number(d.c) || 0,
          open: Number(d.o) || 0,
          high: Number(d.h) || 0,
          low: Number(d.l) || 0,
          volume: Number(d.v) || 0,
          quoteVolume: Number(d.q) || 0,
          eventTime: d.E || Date.now(),
          source: "binance_ws",
        };

        this.tickers.set(d.s, ticker);
        this.update1mCandle(ticker);
      } catch (err) {
        console.error("WS parse error:", err.message);
      }
    });

    this.ws.on("close", () => {
      console.log("Binance WS closed. Reconnecting...");
      this.scheduleReconnect(symbols);
    });

    this.ws.on("error", (err) => {
      console.error("Binance WS error:", err.message);
      try {
        this.ws.close();
      } catch {}
    });
  }

  scheduleReconnect(symbols) {
    clearTimeout(this.reconnectTimer);
    this.reconnectTimer = setTimeout(() => this.start(symbols), 3000);
  }

  stop() {
    clearTimeout(this.reconnectTimer);
    if (this.ws) {
      try {
        this.ws.close();
      } catch {}
    }
  }

  getTicker(symbol) {
    return this.tickers.get(this.normalizeSymbol(symbol));
  }

  getAllTickers() {
    return [...this.tickers.values()];
  }

  update1mCandle(ticker) {
    const minute = Math.floor(ticker.eventTime / 60000) * 60000;
    const key = ticker.symbol;
    const current = this.candles1m.get(key);

    if (!current || current.timestamp !== minute) {
      this.candles1m.set(key, {
        symbol: key,
        open: ticker.price,
        high: ticker.price,
        low: ticker.price,
        close: ticker.price,
        volume: ticker.volume,
        timestamp: minute,
      });
      return;
    }

    current.high = Math.max(current.high, ticker.price);
    current.low = Math.min(current.low, ticker.price);
    current.close = ticker.price;
    current.volume = ticker.volume;
  }

  getCurrent1mCandles() {
    return [...this.candles1m.values()];
  }
}

module.exports = new MarketDataService();