import { useEffect, useRef } from 'react';
import './App.css';

import { DataUpdates, HistoricalDataRequest, Price, UTCTimestamp, Viper as ViperCharts } from "@viper-charts/viper-charts";
// import "@viper-charts/viper-charts/dist/style.css";
import { ViperDatabase } from "./ViperDatabase";

const db = createDB();

function onSaveViperSettings(settings: any) {
  localStorage.setItem("settings", JSON.stringify(settings));
}

async function onRequestTemplates() {
  return await db.templates.where("id").above(0).toArray();
}

async function onSaveTemplate(id: number, { name, config }: any) {
  // Check if template exists at id
  const rows = await db.templates.where("id").equals(id).toArray();
  const row = rows[0];

  if (row) {
    // If so, update it
    await db.templates.update(id, { name, config });
  } else {
    // If not, create it
    await db.templates.add({ name, config });
  }

  return await db.templates.orderBy("id").last();
}

async function onDeleteTemplate(id: number) {
  await db.templates.delete(id);
}

function createDB() {
  const db = new ViperDatabase();
  return db;
}

async function getSourcesFromBinance() {
  const res = await fetch(
    "https://www.binance.com/api/v3/exchangeInfo"
  );
  const json = await res.json();

  const sources: any = {};

  for (const item of json.symbols) {
    sources[item.symbol] = {
      source: "BINANCE",
      name: item.symbol,
      maxItemsPerRequest: 500,
      models: {
        candle: {
          model_id: "candle",
          name: "Candle",
          label: `Binance:${item.symbol}`,
        },
      },
    };
  }

  return sources;
}


const onRequestHistoricalData = async (requests: HistoricalDataRequest[], api: ViperCharts) => {
  for (const {
    source,
    name,
    timeframe,
    dataModels,
    start,
    end,
  } of requests) {
    if (source === "BINANCE") {
      const tf = {
        1000: "1s",
        60000: "1m",
        [60000 * 5]: "5m",
        [60000 * 15]: "15m",
        [60000 * 60]: "1h",
        [60000 * 60 * 4]: "4h",
        [60000 * 60 * 24]: "1d",
      }[timeframe];
      const res = await fetch(`https://www.binance.com/api/v3/klines?symbol=${name}&interval=${tf}&startTime=${start}&endTime=${end}`);
      const json = await res.json();

      for (const dataModel of dataModels) {
        if (dataModel === "candle") {
          const data = new Map() as DataUpdates;
          for (const item of json) {
            const [timestamp, open, high, low, close, volume] = item;
            const time = new Date(timestamp).getTime();
            data.set(time as UTCTimestamp, {
              open: +open as Price,
              high: +high as Price,
              low: +low as Price,
              close: +close as Price,
              volume: +volume
            });
          }
          api.addData({ source, name, timeframe, dataModel }, data);
        }
      }

    }
  }
}


function App() {
  const viperChartRef = useRef<ViperCharts | null>(null);
  const htmlRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    console.log("Initializing...");
    async function initializeViper() {
      // The sources available to ViperCharts
      const sources = {
        BINANCE: await getSourcesFromBinance(),
      };

      if (!htmlRef.current) return;

      if (viperChartRef.current) {
        // destroy if already initializing. In some instances useEffect is called twice.
        viperChartRef.current.destroy();
      };

      // document.getElementById("chart")!,
      viperChartRef.current = new ViperCharts({
        element: htmlRef.current,
        sources,
        settings: JSON.parse(localStorage.getItem("settings")!) || {},
        onRequestHistoricalData,
        onSaveViperSettings,
        onRequestTemplates,
        onSaveTemplate,
        onDeleteTemplate,
      });
    }

    initializeViper();

    return () => {
      viperChartRef.current?.destroy();
      viperChartRef.current = null;
    }
  }, [htmlRef])

  return (
    <div className="App">
      <div ref={htmlRef} id="chart" style={{ width: "100%", height: "100vh" }}></div>
    </div>
  );
}

export default App;
