import { FormatterOptionsArgs, FormatterRow, writeToStream } from "fast-csv"
import fs from "fs"
import kleur from "kleur"
import { Classification } from "./interfaces.js"
import { fetchSymbolsForSource } from "./service/exchange-service.js"
import log from "./service/log.js"

const write = (
  stream: NodeJS.WritableStream,
  rows: FormatterRow[],
  options: FormatterOptionsArgs<FormatterRow, FormatterRow>
): Promise<void> => {
  return new Promise((res, rej) => {
    writeToStream(stream, rows, options)
      .on("error", (err: Error) => rej(err))
      .on("finish", () => res())
  })
}

export const fetchSymbolsMain = async (source: string, quoteAssetFilter?: string, classificationFilter?: string) => {
  const formattedExchange = source.toLowerCase()

  let baseSymbols = await fetchSymbolsForSource(formattedExchange)

  const breakdown = baseSymbols.reduce((acc, symbol) => {
    if (typeof acc[symbol.classification] !== "undefined") {
      acc[symbol.classification] += 1
    } else {
      acc[symbol.classification] = 1
    }
    return acc
  }, {})

  log.info("Parsed symbols classification breakdown:")

  for (const key of Object.keys(Classification)) {
    log.info(`    ${key}: ${breakdown[key] || 0}`)
  }

  if (quoteAssetFilter) {
    baseSymbols = baseSymbols.filter((sym) => sym.quoteAsset.toLowerCase() === quoteAssetFilter.toLowerCase())
  }

  if (classificationFilter) {
    baseSymbols = baseSymbols.filter((sym) => sym.classification.toLowerCase() === classificationFilter.toLowerCase())
  }

  if (!baseSymbols || baseSymbols.length === 0) {
    throw new Error("No symbols fetched or match filters!")
  }

  const rows = baseSymbols.map((baseSymbol) => {
    return {
      symbol: baseSymbol.id,
      instrument: baseSymbol.instrument,
      quote_asset: baseSymbol.quoteAsset,
      alert_name: "",
    }
  })

  const outputPath = `${formattedExchange}${classificationFilter ? "_" + classificationFilter.toLowerCase() : ""}${quoteAssetFilter ? "_" + quoteAssetFilter.toLowerCase() : ""}_symbols.csv`
  const outStream = fs.createWriteStream(outputPath)

  await write(outStream, rows, { headers: true })

  log.success(`Wrote ${rows.length} rows to: ${kleur.blue(outputPath)}`)
}
