// https://github.com/nihalgonsalves/esbuild-plugin-browserslist
// MIT License. Copyright (c) 2021 Nihal Gonsalves
import { z } from "zod"
import browserslist from "browserslist"

export function getDefaultTarget() {
  return getTarget(
    ["Chrome", "Firefox", "Edge", "Safari"].map(browser => `last 2 ${browser} versions`),
  )
}

enum BrowserslistKind {
  Edge = "edge",
  Firefox = "firefox",
  Chrome = "chrome",
  Safari = "safari",
  iOS = "ios_saf",
  Android = "android",
  AndroidChrome = "and_chr",
  AndroidFirefox = "and_ff",
  AndroidUC = "and_uc",
  AndroidQQ = "and_qq",
  Samsung = "samsung",
  Opera = "opera",
  OperaMini = "op_mini",
  OperaMobile = "op_mob",
  IE = "ie",
  IEMobile = "ie_mob",
  BlackBerry = "bb",
  Baidu = "baidu",
  Kaios = "kaios",
  Node = "node",
}

const enum EsbuildEngine {
  Chrome = "chrome",
  Edge = "edge",
  ES = "es",
  Firefox = "firefox",
  Hermes = "hermes",
  IE = "ie",
  IOS = "ios",
  Node = "node",
  Opera = "opera",
  Rhino = "rhino",
  Safari = "safari",
}

const BrowserslistEsbuildMapping: Partial<Record<BrowserslistKind, EsbuildEngine>> = {
  // exact map
  [BrowserslistKind.Edge]: EsbuildEngine.Edge,
  [BrowserslistKind.Firefox]: EsbuildEngine.Firefox,
  [BrowserslistKind.Chrome]: EsbuildEngine.Chrome,
  [BrowserslistKind.Safari]: EsbuildEngine.Safari,
  [BrowserslistKind.iOS]: EsbuildEngine.IOS,
  [BrowserslistKind.Node]: EsbuildEngine.Node,
  [BrowserslistKind.IE]: EsbuildEngine.IE,
  [BrowserslistKind.Opera]: EsbuildEngine.Opera,
  // approximate mapping
  [BrowserslistKind.Android]: EsbuildEngine.Chrome,
  [BrowserslistKind.AndroidChrome]: EsbuildEngine.Chrome,
  [BrowserslistKind.AndroidFirefox]: EsbuildEngine.Firefox,
  // the rest have no equivalent for esbuild
}

const BrowserSchema = z.nativeEnum(BrowserslistKind)
/** 123 or 123.456 or 123.456.789 */
const VersionSchema = z.string().regex(/^(\d+\.\d+\.\d+|\d+\.\d+|\d+)$/)

export function getTarget(targets: string[]): string[] {
  const result = browserslist(targets)
    .map(entry => {
      const [rawBrowser, rawVersionOrRange] = entry.split(" ")

      const rawVersionNormalized = rawVersionOrRange
        // e.g. 13.4-13.7, take the lower range
        ?.replace(/-[\d.]+$/, "")
        // all => replace with 1
        ?.replace("all", "1")

      const browserResult = BrowserSchema.safeParse(rawBrowser)
      const versionResult = VersionSchema.safeParse(rawVersionNormalized)

      if (!browserResult.success || !versionResult.success) {
        return
      }

      const { data: browser } = browserResult
      const { data: version } = versionResult

      const esbuildTarget = BrowserslistEsbuildMapping[browser]

      if (!esbuildTarget) {
        return
      }

      return { target: esbuildTarget, version }
    })
    .filter(Boolean)
    .map(({ target, version }) => `${target}${version}`)

  if (result.length === 0) {
    throw new Error("Could not resolve any esbuild targets")
  }

  return result
}
