import { DOWNLOAD_ITEM_IDS } from './constants'
import { downloadToCSV } from './exports'
import { CSVIcon } from './icons'
import type { DownloadItem } from './types'

interface BuildCsvDownloadItemBase {
  /** Base filename (without extension). The item appends `.csv`. */
  filename: string
  /** Override the menu label. Default `'CSV'`. */
  label?: string
}

/**
 * Args for {@link buildCsvDownloadItem}. A discriminated union: a caller must
 * supply exactly one content source — `getRows` (rows serialised through the
 * shared `toCsvString`) or `getCsv` (a pre-built CSV string). The `?: never`
 * arms make passing both — or neither — a compile-time error.
 */
export type BuildCsvDownloadItemArgs =
  | (BuildCsvDownloadItemBase & {
      /**
       * Builds the CSV rows at click time. Used by most widgets — rows are run
       * through `toCsvString` so escaping (incl. the spreadsheet
       * formula-injection guard) stays consistent across widgets.
       */
      getRows: () => readonly (readonly unknown[])[]
      getCsv?: never
    })
  | (BuildCsvDownloadItemBase & {
      /**
       * Returns a pre-built CSV string at click time. Escape hatch for widgets
       * (e.g. Table) that already serialise their own CSV with bespoke
       * header/cell handling.
       */
      getCsv: () => string
      getRows?: never
    })

/**
 * Builds the standard CSV `DownloadItem` used by every per-widget download
 * config. Centralised so the menu label, icon, and `.csv` filename suffix stay
 * consistent across widgets — mirrors {@link buildPngDownloadItem} so neither
 * format can drift again.
 */
export function buildCsvDownloadItem(
  args: BuildCsvDownloadItemArgs,
): DownloadItem {
  return {
    id: DOWNLOAD_ITEM_IDS.csv,
    label: args.label ?? 'CSV',
    icon: <CSVIcon fontSize='small' />,
    resolve: () => {
      if (args.getCsv) {
        const csv = args.getCsv()
        const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
        const url = URL.createObjectURL(blob)
        return Promise.resolve({
          url,
          filename: `${args.filename}.csv`,
          revoke: () => URL.revokeObjectURL(url),
        })
      }
      const handle = downloadToCSV(args.getRows())
      return Promise.resolve({
        url: handle.url,
        filename: `${args.filename}.csv`,
        revoke: handle.revoke,
      })
    },
  }
}
