package scalibrplugin

import (
	"fmt"

	annotatorlist "github.com/google/osv-scalibr/annotator/list"
	"github.com/google/osv-scalibr/annotator/misc/brewsource"
	apkanno "github.com/google/osv-scalibr/annotator/osduplicate/apk"
	dpkganno "github.com/google/osv-scalibr/annotator/osduplicate/dpkg"
	cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
	detectors "github.com/google/osv-scalibr/detector/list"
	"github.com/google/osv-scalibr/enricher"
	"github.com/google/osv-scalibr/enricher/baseimage"
	"github.com/google/osv-scalibr/enricher/enricherlist"
	transitivedependencypomxml "github.com/google/osv-scalibr/enricher/transitivedependency/pomxml"
	transitivedependencyrequirements "github.com/google/osv-scalibr/enricher/transitivedependency/requirements"
	"github.com/google/osv-scalibr/extractor/filesystem/language/cpp/conanlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/dart/pubspec"
	"github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/depsjson"
	"github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packagesconfig"
	"github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packageslockjson"
	"github.com/google/osv-scalibr/extractor/filesystem/language/erlang/mixlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/golang/gobinary"
	"github.com/google/osv-scalibr/extractor/filesystem/language/golang/gomod"
	"github.com/google/osv-scalibr/extractor/filesystem/language/haskell/cabal"
	"github.com/google/osv-scalibr/extractor/filesystem/language/haskell/stacklock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/java/archive"
	"github.com/google/osv-scalibr/extractor/filesystem/language/java/gradlelockfile"
	"github.com/google/osv-scalibr/extractor/filesystem/language/java/gradleverificationmetadataxml"
	"github.com/google/osv-scalibr/extractor/filesystem/language/java/pomxml"
	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/bunlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagelockjson"
	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/pnpmlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/yarnlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/php/composerlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/pdmlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/pipfilelock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/poetrylock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/pylock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/requirements"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/uvlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/python/wheelegg"
	"github.com/google/osv-scalibr/extractor/filesystem/language/r/renvlock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/ruby/gemfilelock"
	"github.com/google/osv-scalibr/extractor/filesystem/language/rust/cargoauditable"
	"github.com/google/osv-scalibr/extractor/filesystem/language/rust/cargolock"
	extractors "github.com/google/osv-scalibr/extractor/filesystem/list"
	"github.com/google/osv-scalibr/extractor/filesystem/os/apk"
	"github.com/google/osv-scalibr/extractor/filesystem/os/dpkg"
	"github.com/google/osv-scalibr/extractor/filesystem/os/homebrew"
	"github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx"
	"github.com/google/osv-scalibr/extractor/filesystem/sbom/spdx"
	"github.com/google/osv-scanner/v2/internal/scalibrextract/filesystem/vendored"
	"github.com/google/osv-scanner/v2/internal/scalibrextract/language/javascript/nodemodules"
	"github.com/google/osv-scanner/v2/internal/scalibrextract/language/osv/osvscannerjson"
	"github.com/google/osv-scanner/v2/internal/scalibrextract/vcs/gitrepo"
	"github.com/google/osv-scanner/v2/internal/version"
)

var detectorPresets = map[string]detectors.InitMap{
	"cis":         detectors.CIS,
	"govulncheck": detectors.Govulncheck,
	"untested":    detectors.Untested,
	"weakcreds":   detectors.Weakcredentials,
}

var ExtractorPresets = map[string]extractors.InitMap{
	"sbom": {
		spdx.Name: {spdx.New},
		cdx.Name:  {cdx.New},
	},
	"lockfile": {
		// C
		conanlock.Name: {conanlock.New},

		// Erlang
		mixlock.Name: {mixlock.New},

		// Flutter
		pubspec.Name: {pubspec.New},

		// Go
		gomod.Name: {gomod.New},

		// Java
		gradlelockfile.Name:                {gradlelockfile.New},
		gradleverificationmetadataxml.Name: {gradleverificationmetadataxml.New},
		pomxml.Name:                        {pomxml.New},

		// Javascript
		packagelockjson.Name: {packagelockjson.New},
		pnpmlock.Name:        {pnpmlock.New},
		yarnlock.Name:        {yarnlock.New},
		bunlock.Name:         {bunlock.New},

		// PHP
		composerlock.Name: {composerlock.New},

		// Python
		pipfilelock.Name:  {pipfilelock.New},
		pdmlock.Name:      {pdmlock.New},
		poetrylock.Name:   {poetrylock.New},
		pylock.Name:       {pylock.New},
		requirements.Name: {requirements.New},
		uvlock.Name:       {uvlock.New},

		// R
		renvlock.Name: {renvlock.New},

		// Ruby
		gemfilelock.Name: {gemfilelock.New},

		// Rust
		cargolock.Name: {cargolock.New},

		// NuGet
		depsjson.Name:         {depsjson.New},
		packagesconfig.Name:   {packagesconfig.New},
		packageslockjson.Name: {packageslockjson.New},

		// Haskell
		cabal.Name:     {cabal.New},
		stacklock.Name: {stacklock.New},

		osvscannerjson.Name: {osvscannerjson.New},

		// --- OS "lockfiles" ---
		// These have very strict FileRequired paths, so we can safely enable them for source scanning as well.
		// Alpine
		apk.Name: {apk.New},
		// Debian
		dpkg.Name: {dpkg.New},
	},
	"directory": {
		gitrepo.Name:  {gitrepo.New},
		vendored.Name: {vendored.New},
	},
	"artifact": {
		// --- Project artifacts ---
		// Python
		wheelegg.Name: {wheelegg.New},
		// Java
		archive.Name: {archive.New},
		// Go
		gobinary.Name: {gobinary.New},
		// Javascript
		nodemodules.Name: {nodemodules.New},
		// Rust
		cargoauditable.Name: {cargoauditable.New},

		// --- OS packages ---
		// Alpine
		apk.Name: {apk.New},
		// Debian
		dpkg.Name: {dpkg.New},
		// Homebrew
		homebrew.Name: {homebrew.New},
	},
}

var enricherPresets = map[string]enricherlist.InitMap{
	"artifact": {
		baseimage.Name: {baseImageEnricher},
	},
	"vulns":    enricherlist.VulnMatching,
	"licenses": enricherlist.License,
	"transitive": {
		transitivedependencyrequirements.Name: {transitivedependencyrequirements.New},
		transitivedependencypomxml.Name:       {transitivedependencypomxml.New},
	},
}

var annotatorPresets = map[string]annotatorlist.InitMap{
	"artifact": {
		apkanno.Name:    {apkanno.New},
		dpkganno.Name:   {dpkganno.New},
		brewsource.Name: {brewsource.New},
	},
}

func baseImageEnricher(_ *cpb.PluginConfig) (enricher.Enricher, error) {
	baseImageEnricher, err := baseimage.New(&cpb.PluginConfig{
		UserAgent: "osv-scanner_scan/" + version.OSVVersion,
	})

	if err != nil {
		return nil, fmt.Errorf("unable to initialize base image enricher: %w", err)
	}

	return baseImageEnricher, nil
}
