package debian

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/ulikunitz/xz"
)

// DependencyResolver provides comprehensive Debian dependency resolution
type DependencyResolver struct {
	resolver   *Resolver
	cache      *dependencyCache
	httpClient *http.Client
	mirrors    []string
	suites     []string
	components []string
	arch       string
}

// dependencyCache caches resolved dependencies
type dependencyCache struct {
	mu       sync.RWMutex
	deps     map[string]*PackageDeps
	notFound map[string]bool            // cache of packages that were not found
	srcMap   map[string]string          // binary pkg name -> source pkg name
	inFlight map[string]*sync.WaitGroup // track in-flight requests
}

// PackageDeps represents Debian package dependencies
type PackageDeps struct {
	Package      string
	Source       string
	Version      string
	Depends      []string
	BuildDepends []string
	Suggests     []string
	Recommends   []string
	Conflicts    []string
	Provides     []string
}

// NewDependencyResolver creates a comprehensive Debian dependency resolver
func NewDependencyResolver() *DependencyResolver {
	return &DependencyResolver{
		resolver: NewResolver(),
		cache: &dependencyCache{
			deps:     make(map[string]*PackageDeps),
			notFound: make(map[string]bool),
			srcMap:   make(map[string]string),
			inFlight: make(map[string]*sync.WaitGroup),
		},
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
		mirrors: []string{
			"https://deb.debian.org/debian",
			"https://ftp.debian.org/debian",
			"https://mirrors.kernel.org/debian",
		},
		suites:     []string{"sid", "unstable", "testing", "stable"},
		components: []string{"main", "contrib", "non-free"},
		arch:       "amd64",
	}
}

// ResolveDependencies resolves all dependencies for a Debian binary package
func (r *DependencyResolver) ResolveDependencies(pkgName string) (*PackageDeps, error) {
	// Check "not found" cache first to avoid repeated lookups
	if r.cache.getNotFound(pkgName) {
		return nil, fmt.Errorf("package %s not found (cached)", pkgName)
	}

	// Check cache first
	if cached := r.cache.get(pkgName); cached != nil {
		return cached, nil
	}

	// Try to find in Sources files (for build-deps) or Packages files (for runtime deps)
	deps, err := r.resolveFromDebian(pkgName)
	if err != nil {
		// Cache the failure to avoid repeated lookups
		r.cache.setNotFound(pkgName)
		return nil, err
	}

	// Cache result
	r.cache.set(pkgName, deps)

	return deps, nil
}

// BinaryToSource maps a Debian binary package name to its source package name
func (r *DependencyResolver) BinaryToSource(binaryPkg string) (string, error) {
	// Check "not found" cache first
	if r.cache.getNotFound(binaryPkg) {
		return "", fmt.Errorf("package %s not found (cached)", binaryPkg)
	}

	// Check srcMap cache
	if src := r.cache.getSource(binaryPkg); src != "" {
		return src, nil
	}

	// Try built-in mappings first (fast path)
	if src := mapBinaryToSourceFast(binaryPkg); src != "" {
		r.cache.setSource(binaryPkg, src)
		return src, nil
	}

	// Check if request is already in flight
	wg, inFlight := r.cache.startInFlight(binaryPkg)
	if inFlight {
		// Wait for the in-flight request to complete
		wg.Wait()
		// Check cache again after waiting
		if r.cache.getNotFound(binaryPkg) {
			return "", fmt.Errorf("package %s not found (cached after wait)", binaryPkg)
		}
		if src := r.cache.getSource(binaryPkg); src != "" {
			return src, nil
		}
		return "", fmt.Errorf("package %s not found after wait", binaryPkg)
	}

	// We are the first request for this package
	defer func() {
		// finishInFlight will be called after we complete the lookup
	}()

	// Look up in Debian Sources
	srcInfo, err := r.resolver.ResolveSource(binaryPkg)
	if err != nil {
		// Cache the failure and mark in-flight as complete
		r.cache.finishInFlight(binaryPkg, true)
		return "", fmt.Errorf("cannot resolve source for %s: %w", binaryPkg, err)
	}

	// Cache success and mark in-flight as complete
	r.cache.setSource(binaryPkg, srcInfo.SourcePackage)
	r.cache.finishInFlight(binaryPkg, false)
	return srcInfo.SourcePackage, nil
}

// ResolveDependencyChain resolves full dependency chain for a package
func (r *DependencyResolver) ResolveDependencyChain(rootPkg string, includeBuildDeps bool) ([]string, error) {
	visited := make(map[string]bool)
	result := make([]string, 0)
	queue := []string{rootPkg}

	for len(queue) > 0 {
		pkg := queue[0]
		queue = queue[1:]

		if visited[pkg] {
			continue
		}
		visited[pkg] = true

		// Get package dependencies
		deps, err := r.ResolveDependencies(pkg)
		if err != nil {
			// Try to resolve as source package
			srcPkg, srcErr := r.BinaryToSource(pkg)
			if srcErr != nil {
				continue // Skip unresolved
			}
			if !visited[srcPkg] {
				result = append(result, srcPkg)
			}
			continue
		}

		result = append(result, pkg)

		// Add runtime dependencies
		for _, dep := range deps.Depends {
			depName := r.extractDepName(dep)
			if !visited[depName] {
				queue = append(queue, depName)
			}
		}

		// Add build dependencies if requested
		if includeBuildDeps {
			for _, dep := range deps.BuildDepends {
				depName := r.extractDepName(dep)
				if !visited[depName] {
					queue = append(queue, depName)
				}
			}
		}
	}

	return result, nil
}

// extractDepName extracts package name from dependency string (e.g., "pkg (>= 1.0)" -> "pkg")
func (r *DependencyResolver) extractDepName(dep string) string {
	// Remove version constraints
	re := regexp.MustCompile(`^([a-zA-Z0-9+.-]+)`)
	matches := re.FindStringSubmatch(dep)
	if len(matches) > 1 {
		return matches[1]
	}
	return dep
}

// resolveFromDebian attempts to resolve dependencies from Debian repository
func (r *DependencyResolver) resolveFromDebian(pkgName string) (*PackageDeps, error) {
	// Try to find binary package info from Packages files
	for _, mirror := range r.mirrors {
		for _, suite := range r.suites {
			for _, component := range r.components {
				deps, err := r.fetchBinaryPackageInfo(mirror, suite, component, pkgName)
				if err == nil && deps != nil {
					return deps, nil
				}
			}
		}
	}

	return nil, fmt.Errorf("package %s not found in Debian repositories", pkgName)
}

// fetchBinaryPackageInfo fetches package info from Packages.xz
func (r *DependencyResolver) fetchBinaryPackageInfo(mirror, suite, component, pkgName string) (*PackageDeps, error) {
	url := fmt.Sprintf("%s/dists/%s/%c%s/binary-%s/Packages.xz",
		mirror, suite, component[0], component[1:], r.arch)

	resp, err := r.httpClient.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
	}

	// Decompress xz
	xzReader, err := xz.NewReader(resp.Body)
	if err != nil {
		return nil, err
	}

	// Parse Packages file looking for our package
	return r.parsePackagesFile(xzReader, pkgName)
}

// parsePackagesFile parses Debian Packages file to find package info
func (dr *DependencyResolver) parsePackagesFile(reader io.Reader, targetPkg string) (*PackageDeps, error) {
	scanner := bufio.NewScanner(reader)
	var currentPkg *PackageDeps
	inTarget := false

	for scanner.Scan() {
		line := scanner.Text()

		// Empty line = end of paragraph
		if line == "" {
			if inTarget && currentPkg != nil {
				return currentPkg, nil
			}
			currentPkg = nil
			inTarget = false
			continue
		}

		// Check if this is our target package
		if strings.HasPrefix(line, "Package: ") {
			pkg := strings.TrimPrefix(line, "Package: ")
			if pkg == targetPkg {
				inTarget = true
				currentPkg = &PackageDeps{Package: pkg}
			}
		}

		if !inTarget || currentPkg == nil {
			continue
		}

		// Parse fields
		switch {
		case strings.HasPrefix(line, "Source: "):
			currentPkg.Source = strings.TrimPrefix(line, "Source: ")
		case strings.HasPrefix(line, "Version: "):
			currentPkg.Version = strings.TrimPrefix(line, "Version: ")
		case strings.HasPrefix(line, "Depends: "):
			currentPkg.Depends = dr.parseDepLine(strings.TrimPrefix(line, "Depends: "))
		case strings.HasPrefix(line, "Suggests: "):
			currentPkg.Suggests = dr.parseDepLine(strings.TrimPrefix(line, "Suggests: "))
		case strings.HasPrefix(line, "Recommends: "):
			currentPkg.Recommends = dr.parseDepLine(strings.TrimPrefix(line, "Recommends: "))
		case strings.HasPrefix(line, "Conflicts: "):
			currentPkg.Conflicts = dr.parseDepLine(strings.TrimPrefix(line, "Conflicts: "))
		case strings.HasPrefix(line, "Provides: "):
			currentPkg.Provides = dr.parseDepLine(strings.TrimPrefix(line, "Provides: "))
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	if inTarget && currentPkg != nil {
		return currentPkg, nil
	}

	return nil, fmt.Errorf("package not found")
}

// parseDepLine parses dependency line (handles alternatives with |)
func (r *DependencyResolver) parseDepLine(line string) []string {
	result := make([]string, 0)

	// Split by comma (separate dependencies)
	parts := strings.Split(line, ",")
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part != "" {
			result = append(result, part)
		}
	}

	return result
}

// Cache methods
func (c *dependencyCache) get(pkg string) *PackageDeps {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.deps[pkg]
}

func (c *dependencyCache) getNotFound(pkg string) bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.notFound[pkg]
}

func (c *dependencyCache) setNotFound(pkg string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.notFound[pkg] = true
}

// startInFlight starts tracking an in-flight request, returns wait group if already in flight
func (c *dependencyCache) startInFlight(pkg string) (*sync.WaitGroup, bool) {
	c.mu.Lock()
	defer c.mu.Unlock()

	// Check if already cached as not found
	if c.notFound[pkg] {
		return nil, false
	}

	// Check if already in flight
	if wg, exists := c.inFlight[pkg]; exists {
		return wg, true
	}

	// Create new wait group for this request
	wg := &sync.WaitGroup{}
	wg.Add(1)
	c.inFlight[pkg] = wg
	return wg, false
}

// finishInFlight marks in-flight request as complete
func (c *dependencyCache) finishInFlight(pkg string, notFound bool) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if wg, exists := c.inFlight[pkg]; exists {
		delete(c.inFlight, pkg)
		if notFound {
			c.notFound[pkg] = true
		}
		wg.Done()
	}
}

func (c *dependencyCache) set(pkg string, deps *PackageDeps) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.deps[pkg] = deps
}

func (c *dependencyCache) getSource(binary string) string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.srcMap[binary]
}

func (c *dependencyCache) setSource(binary, source string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.srcMap[binary] = source
}

// mapBinaryToSourceFast provides fast static mappings for common packages
func mapBinaryToSourceFast(binary string) string {
	// Comprehensive mapping of Debian binary packages to source packages
	mappings := map[string]string{
		// Essential build tools
		"cmake":       "cmake",
		"ninja-build": "ninja-build",
		"meson":       "meson",
		"pkg-config":  "pkgconf",
		"pkgconf":     "pkgconf",

		// Compilers
		"gcc":   "gcc-defaults",
		"g++":   "gcc-defaults",
		"clang": "llvm-defaults",

		// SSL/TLS
		"libssl-dev": "openssl",
		"libssl3":    "openssl",
		"openssl":    "openssl",

		// Compression
		"zlib1g-dev":  "zlib",
		"zlib1g":      "zlib",
		"libbz2-dev":  "bzip2",
		"liblzma-dev": "xz-utils",
		"libzstd-dev": "zstd",

		// XML
		"libxml2-dev":  "libxml2",
		"libxml2":      "libxml2",
		"libxslt1-dev": "libxslt",

		// JSON
		"libjson-c-dev": "json-c",
		"libjson-c5":    "json-c",

		// cURL
		"libcurl4-openssl-dev": "curl",
		"libcurl4-gnutls-dev":  "curl",
		"curl":                 "curl",

		// Database
		"libsqlite3-dev": "sqlite3",
		"libsqlite3-0":   "sqlite3",

		// Terminal/UI
		"libncurses-dev":  "ncurses",
		"libncurses6":     "ncurses",
		"libreadline-dev": "readline",
		"libreadline8":    "readline",

		// Image
		"libpng-dev":  "libpng1.6",
		"libpng16-16": "libpng1.6",
		"libjpeg-dev": "libjpeg-turbo",
		"libtiff-dev": "tiff",

		// Crypto
		"libgcrypt20-dev":  "libgcrypt20",
		"libgpg-error-dev": "libgpg-error",

		// GNUTLS
		"libgnutls28-dev": "gnutls28",

		// PCRE
		"libpcre3-dev": "pcre3",
		"libpcre2-dev": "pcre2",

		// Expat
		"libexpat1-dev": "expat",

		// FFI
		"libffi-dev": "libffi",

		// UUID
		"libuuid-dev": "util-linux",

		// Git
		"git": "git",

		// Flex/Bison
		"flex":  "flex",
		"bison": "bison",
		"m4":    "m4",

		// Autotools
		"autoconf": "autoconf",
		"automake": "automake",
		"libtool":  "libtool",

		// Gettext
		"gettext":          "gettext",
		"libgettextpo-dev": "gettext",

		// Lua
		"liblua5.1-dev": "lua5.1",
		"liblua5.4-dev": "lua5.4",

		// Python
		"python3-dev": "python3-defaults",
		"python3":     "python3-defaults",

		// Perl
		"perl": "perl",

		// Procps
		"procps": "procps-ng",

		// Iconv
		"libiconv-hook-dev": "libiconv",

		// ICU
		"libicu-dev": "icu",

		// HarfBuzz
		"libharfbuzz-dev": "harfbuzz",

		// FontConfig
		"libfontconfig-dev": "fontconfig",

		// Freetype
		"libfreetype-dev": "freetype",

		// Cairo
		"libcairo2-dev": "cairo",

		// Pango
		"libpango1.0-dev": "pango1.0",

		// GDK-Pixbuf
		"libgdk-pixbuf-2.0-dev": "gdk-pixbuf",

		// GLib
		"libglib2.0-dev": "glib2.0",

		// GObject introspection
		"gobject-introspection": "gobject-introspection",

		// ATK
		"libatk1.0-dev": "atk1.0",

		// GTK
		"libgtk-3-dev": "gtk+3.0",
		"libgtk-4-dev": "gtk4",

		// GLibmm
		"libglibmm-2.4-dev": "glibmm2.4",

		// X11
		"libx11-dev":        "libx11",
		"libxext-dev":       "libxext",
		"libxrender-dev":    "libxrender",
		"libxft-dev":        "libxft",
		"libxpm-dev":        "libxpm",
		"libxmu-dev":        "libxmu",
		"libxaw7-dev":       "libxaw",
		"libxfixes-dev":     "libxfixes",
		"libxinerama-dev":   "libxinerama",
		"libxrandr-dev":     "libxrandr",
		"libxcursor-dev":    "libxcursor",
		"libxcomposite-dev": "libxcomposite",
		"libxdamage-dev":    "libxdamage",
		"libxkbfile-dev":    "libxkbfile",

		// XCB
		"libxcb1-dev":         "libxcb",
		"libxcb-keysyms1-dev": "xcb-util-keysyms",

		// Xt
		"libxt-dev": "libxt",

		// SM/ICE
		"libsm-dev":  "libsm",
		"libice-dev": "libice",

		// Xtrans
		"libxtrans-dev": "libxtrans",

		// X11proto
		"x11proto-dev":       "xorgproto",
		"xorg-sgml-doctools": "xorg-sgml-doctools",

		// Wayland
		"libwayland-dev":    "wayland",
		"wayland-protocols": "wayland-protocols",

		// OpenGL
		"libgl-dev":        "libglvnd",
		"libgl1-mesa-dev":  "mesa",
		"libegl1-mesa-dev": "mesa",
		"libgbm-dev":       "mesa",

		// Vulkan
		"libvulkan-dev": "vulkan-loader",

		// Shaderc
		"libshaderc-dev": "shaderc",

		// SPIRV
		"libspirv-tools-dev": "spirv-tools",

		// PulseAudio
		"libpulse-dev": "pulseaudio",

		// ALSA
		"libasound2-dev": "alsa-lib",

		// JACK
		"libjack-dev": "jack-audio-connection-kit",

		// PipeWire
		"libpipewire-0.3-dev": "pipewire",

		// D-Bus
		"libdbus-1-dev": "dbus",

		// GMP
		"libgmp-dev": "gmp",

		// MPFR
		"libmpfr-dev": "mpfr",

		// MPC
		"libmpc-dev": "mpc",

		// GPGME
		"libgpgme-dev": "gpgme1.0",

		// Assuan
		"libassuan-dev": "libassuan",

		// KSBA
		"libksba-dev": "libksba",

		// NTBTLS
		"libntbtls-dev": "ntbtls",

		// OpenLDAP
		"libldap2-dev": "openldap",

		// SASL
		"libsasl2-dev": "cyrus-sasl2",

		// Kerberos
		"libkrb5-dev": "krb5",

		// Keyutils
		"libkeyutils-dev": "keyutils",

		// Nettle
		"libnettle-dev": "nettle",

		// Hogweed
		"libhogweed6": "nettle",

		// TASN1
		"libtasn1-6-dev": "libtasn1-6",

		// IDN2
		"libidn2-dev": "libidn2",

		// Unistring
		"libunistring-dev": "libunistring",

		// PSL
		"libpsl-dev": "libpsl",

		// BROTLI
		"libbrotli-dev": "brotli",

		// NGHTTP2
		"libnghttp2-dev": "nghttp2",

		// Systemd
		"libsystemd-dev": "systemd",

		// Elogind
		"libelogind-dev": "elogind",

		// UPower
		"libupower-glib-dev": "upower",

		// UDisks
		"libudisks2-dev": "udisks2",

		// Polkit
		"libpolkit-gobject-1-dev": "policykit-1",

		// ConsoleKit
		"libck-connector-dev": "consolekit",

		// UDEV
		"libudev-dev": "systemd",

		// Eudev
		"libeudev-dev": "eudev",

		// KMod
		"libkmod-dev": "kmod",

		// PCIUtils
		"libpci-dev": "pciutils",

		// USBUtils
		"libusb-1.0-0-dev": "usbutils",

		// Libusb
		"libusb-1.0-dev": "libusb-1.0",

		// HIDAPI
		"libhidapi-dev": "hidapi",

		// SDL2
		"libsdl2-dev": "sdl2",

		// OpenAL
		"libopenal-dev": "openal-soft",

		// Ogg
		"libogg-dev": "libogg",

		// Vorbis
		"libvorbis-dev": "libvorbis",

		// FLAC
		"libflac-dev": "flac",

		// Opus
		"libopus-dev": "opus",

		// Theora
		"libtheora-dev": "libtheora",

		// VPX
		"libvpx-dev": "libvpx",

		// AOM
		"libaom-dev": "aom",

		// DAV1D
		"libdav1d-dev": "dav1d",

		// FFmpeg
		"libavcodec-dev":  "ffmpeg",
		"libavformat-dev": "ffmpeg",
		"libavutil-dev":   "ffmpeg",

		// X264
		"libx264-dev": "x264",

		// X265
		"libx265-dev": "x265",

		// WebP
		"libwebp-dev": "libwebp",

		// OpenEXR
		"libopenexr-dev": "openexr",

		// Imath
		"libimath-dev": "imath",

		// OpenJPEG
		"libopenjp2-7-dev": "openjpeg2",

		// LittleCMS
		"liblcms2-dev": "lcms2",

		// "libreadline-dev":     "readline",

		// History
		"libhistory-dev": "readline",

		// Termcap
		"libtinfo-dev": "ncurses",

		// Curses
		"libcurses-dev": "ncurses",

		// Panel
		"libpanel-dev": "ncurses",

		// Menu
		"libmenu-dev": "ncurses",

		// Form
		"libform-dev": "ncurses",

		// SLANG
		"libslang2-dev": "slang2",

		// Newt
		"libnewt-dev": "newt",

		// CDK
		"libcdk5-dev": "cdk",

		// ADNS
		"libadns1-dev": "adns",

		// Anet
		"libanet-dev": "anet",

		// APR
		"libapr1-dev": "apr",

		// APR-Util
		"libaprutil1-dev": "apr-util",

		// ASpell
		"libaspell-dev": "aspell",

		// Hunspell
		"libhunspell-dev": "hunspell",

		// HSpell
		"libhspell-dev": "hspell",

		// Voikko
		"libvoikko-dev": "libvoikko",

		// Zemberek
		"libzemberek-dev": "zemberek",

		// Zinnia
		"libzinnia-dev": "zinnia",

		// Teckit
		"libteckit-dev": "teckit",

		// Graphite
		"libgraphite2-dev": "graphite2",

		// Raptor
		"libraptor2-dev": "raptor2",

		// Rasqal
		"librasqal3-dev": "rasqal",

		// Redland
		"librdf0-dev": "redland",

		// Serd
		"libserd-dev": "serd",

		// Sord
		"libsord-dev": "sord",

		// SRATOM
		"libsratom-dev": "sratom",

		// LILV
		"liblilv-dev": "lilv",

		// LV2
		"lv2-dev": "lv2",

		// SUIL
		"libsuil-dev": "suil",

		// DSSI
		"libdssi-dev": "dssi",

		// LADSPA
		"libladspa-sdk-dev": "ladspa-sdk",

		// VST
		"vst3sdk-dev": "vst3sdk",

		// CLAP
		"clap-dev": "clap",

		// BS2B
		"libbs2b-dev": "libbs2b",

		// LADSPA (again)
		"ladspa-sdk": "ladspa-sdk",

		// CAPS
		"caps": "caps",

		// TAP
		"tap-plugins": "tap-plugins",

		// CMT
		"cmt": "cmt",

		// SWH
		"swh-plugins": "swh-plugins",

		// FFAUDIO
		"libffado-dev": "libffado",

		// ALSA (again)
		"libasound-dev": "alsa-lib",

		// FireWire
		"libraw1394-dev": "libraw1394",

		// IEC61883
		"libiec61883-dev": "libiec61883",

		// AV1394
		"libavc1394-dev": "libavc1394",

		// DC1394
		"libdc1394-dev": "libdc1394",

		// GLIB (already defined above)
		// "libglib2.0-dev":      "glib2.0",

		// GObject (again)
		"libgobject2.0-dev": "glib2.0",

		// GModule (again)
		"libgmodule2.0-dev": "glib2.0",

		// GIO (again)
		"libgio2.0-dev": "glib2.0",

		// GThread (again)
		"libgthread2.0-dev": "glib2.0",

		// Mount
		"libmount-dev": "util-linux",

		// BLKID
		"libblkid-dev": "util-linux",

		// UUID (already defined above)
		// "libuuid-dev":         "util-linux",

		// SELinux
		"libselinux1-dev": "selinux",

		// SEManage
		"libsemanage-dev": "semanage",

		// SECureDB
		"libsecomp-dev": "libseccomp",

		// Audit
		"libauparse-dev": "audit",

		// E2FSProgs
		"libext2fs-dev": "e2fsprogs",

		// ComErr
		"libcom-err2-dev": "e2fsprogs",

		// SS
		"libss2-dev": "e2fsprogs",

		// Magic
		"libmagic-dev": "file",

		// ACap
		"libcap-dev": "libcap2",

		// ACap-NG
		"libcap-ng-dev": "libcap-ng",

		// AppArmor
		"libapparmor-dev": "apparmor",

		// Tomoyo
		"libtomoyotools-dev": "tomoyo-tools",

		// SMACK
		"libsmack-dev": "smack",

		// TOMOYO (again)
		"tomoyo-tools": "tomoyo-tools",

		// IMA-EVM
		"ima-evm-utils": "ima-evm-utils",

		// TSS2
		"libtss2-dev": "tpm2-tss",

		// FAPI
		"libfapi-dev": "tpm2-tss",

		// TCTI
		"libtcti-dev": "tpm2-tss",

		// ESYS
		"libesys-dev": "tpm2-tss",

		// MU
		"libmu-dev": "mailutils",

		// Guile
		"guile-3.0-dev": "guile-3.0",

		// GMP (already defined at line 346)
		// "libgmp-dev": "gmp",

		// Ncurses (variant)
		"libncursesw5-dev": "ncurses",

		// Readline (already defined at line 369)
		// "libreadline-dev": "readline",

		// Texinfo
		"texinfo": "texinfo",

		// TexLive
		"texlive": "texlive-base",

		// Doxygen
		"doxygen": "doxygen",

		// Graphviz
		"graphviz-dev": "graphviz",

		// PLplot
		"libplplot-dev": "plplot",

		// GSL
		"libgsl-dev": "gsl",

		// FFTW
		"libfftw3-dev": "fftw3",

		// BLAS
		"libblas-dev": "blas",

		// LAPACK
		"liblapack-dev": "lapack",

		// ATLAS
		"libatlas-base-dev": "atlas",

		// OpenBLAS
		"libopenblas-dev": "openblas",

		// SuiteSparse
		"libsuitesparse-dev": "suitesparse",

		// ARPACK
		"libarpack2-dev": "arpack",

		// PARPACK
		"libparpack2-dev": "arpack",

		// SuperLU
		"libsuperlu-dev": "superlu",

		// METIS
		"libmetis-dev": "metis",

		// Scotch
		"libscotch-dev": "scotch",

		// MUMPS
		"libmumps-dev": "mumps",

		// Hypre
		"libhypre-dev": "hypre",

		// PETSc
		"libpetsc-dev": "petsc",

		// SLEPc
		"libslepc-dev": "slepc",

		// Trilinos
		"trilinos-all-dev": "trilinos",

		// Boost
		"libboost-all-dev": "boost-defaults",

		// Eigen3
		"libeigen3-dev": "eigen3",

		// Dune
		"libdune-common-dev": "dune-common",

		// FEniCS
		"fenics": "fenics",

		// Deal.II
		"libdeal.ii-dev": "deal.ii",

		// CGAL
		"libcgal-dev": "cgal",

		// PPL
		"libppl-dev": "ppl",

		// NTL
		"libntl-dev": "ntl",

		// FLINT
		"libflint-dev": "flint",

		// Arb
		"libarb-dev": "arb",

		// Antic
		"libantic-dev": "antic",

		// Calcium
		"libcalcium-dev": "calcium",

		// NF
		"libnf-dev": "nf",

		// GF2X
		"libgf2x-dev": "gf2x",

		// M4RI
		"libm4ri-dev": "m4ri",

		// M4RIE
		"libm4rie-dev": "m4rie",

		// LinBox
		"liblinbox-dev": "linbox",

		// IML
		"libiml-dev": "iml",

		// BLAD
		"libblad-dev": "blad",

		// CADO
		"cado-nfs-dev": "cado-nfs",

		// PARI
		"libpari-dev": "pari",

		// Symmetrica
		"symmetrica-dev": "symmetrica",

		// Lidia
		"liblidia-dev": "lidia",

		// NTL (already defined above)
		// "libntl-dev":          "ntl",

		// OpenSSL (already defined above)
		// "libssl-dev":          "openssl",

		// OpenSSH
		"libssh-dev": "libssh",

		// OpenSSH2
		"libssh2-1-dev": "libssh2",

		// Neon
		"libneon27-dev": "neon27",

		// Serf
		"libserf-1-dev": "serf",

		// Subversion
		"libsvn-dev": "subversion",

		// RHash
		"librhash-dev": "rhash",

		// XXHASH
		"libxxhash-dev": "xxhash",

		// HighwayHash
		"libhighwayhash-dev": "highwayhash",

		// CityHash
		"libcityhash-dev": "cityhash",

		// MurmurHash
		"libmurmurhash-dev": "murmurhash",

		// SpookyHash
		"libspookyhash-dev": "spookyhash",

		// FarmHash
		"libfarmhash-dev": "farmhash",

		// MetroHash
		"libmetrohash-dev": "metrohash",

		// t1ha
		"libt1ha-dev": "t1ha",

		// PRVHASH
		"libprvhash-dev": "prvhash",

		// Wyhash
		"libwyhash-dev": "wyhash",

		// rapidhash
		"librapidhash-dev": "rapidhash",

		// SHA3
		"libsha3-dev": "sha3",

		// Blake2
		"libblake2-dev": "blake2",

		// Blake3
		"libblake3-dev": "blake3",

		// KangarooTwelve
		"libk12-dev": "k12",

		// SHAKE
		"libshake-dev": "sha3",

		// TupleHash
		"libtuplehash-dev": "sha3",

		// ParallelHash
		"libparallelhash-dev": "sha3",

		// cSHAKE
		"libcshake-dev": "sha3",

		// TurboSHAKE
		"libturboshake-dev": "turbo",

		// Ascon
		"libascon-dev": "ascon",

		// ISAP
		"libisap-dev": "isap",

		// DryGascon
		"libdrygascon-dev": "drygascon",

		// Gimli
		"libgimli-dev": "gimli",

		// Xoodoo
		"libxoodoo-dev": "xoodoo",

		// Keccak
		"libkeccak-dev": "keccak",

		// FNV
		"libfnv-dev": "fnv",

		// Murmur (already defined above)
		"libmurmurhash3-dev": "murmurhash",

		// CityHash (already defined above)
		// "libcityhash-dev":     "cityhash",
	}

	return mappings[binary]
}
