const CSV_PARSER = /(,|\r?\n|\r|^|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))/gi

// CSV fetch and parse.
export async function fetchCsv (src) {
  const res = await fetch(src)
  if (!res.ok) {
    throw new Error(`Failed to load ${src} (${res.status})`)
  }
  const text = await res.text()
  return parseCsv(text || '')
}

// Parse CSV string.
function parseCsv (csv) {
  const trimmedCsv = csv.trim()
  const regex = CSV_PARSER
  const lines = [[]]
  let match
  while ((match = regex.exec(trimmedCsv))) {
    const [separator, quoted, unquoted] = match.slice(1)
    if (separator.length && separator !== ',') {
      lines.push([])
    }

    lines.at(-1).push(quoted ? quoted.replaceAll('""', '"') : unquoted)
  }

  const headers = lines[0].map(header => header.trim())
  return lines.slice(1).map((line, lineIndex) => line.reduce((obj, value, index) => {
    obj[headers[index]] = value?.trim?.() || value
    return obj
  }, { key: lineIndex }))
}
