package types

import (
	"github.com/aquasecurity/trivy-db/pkg/types"
	ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
)

// DetectedVulnerability holds the information of detected vulnerabilities
type DetectedVulnerability struct {
	VulnerabilityID  string         `json:",omitempty"`
	VendorIDs        []string       `json:",omitempty"`
	PkgID            string         `json:",omitempty"` // It is used to construct dependency graph.
	PkgName          string         `json:",omitempty"`
	PkgPath          string         `json:",omitempty"` // It will be filled in the case of language-specific packages such as egg/wheel and gemspec
	InstalledVersion string         `json:",omitempty"`
	FixedVersion     string         `json:",omitempty"`
	Layer            ftypes.Layer   `json:",omitempty"`
	SeveritySource   types.SourceID `json:",omitempty"`
	PrimaryURL       string         `json:",omitempty"`
	Ref              string         `json:",omitempty"`

	// DataSource holds where the advisory comes from
	DataSource *types.DataSource `json:",omitempty"`

	// Custom is for extensibility and not supposed to be used in OSS
	Custom interface{} `json:",omitempty"`

	// Embed vulnerability details
	types.Vulnerability
}

// BySeverity implements sort.Interface based on the Severity field.
type BySeverity []DetectedVulnerability

// Len returns the length of DetectedVulnerabilities
func (v BySeverity) Len() int { return len(v) }

// Less compares 2 DetectedVulnerabilities based on package name, severity and vulnerabilityID
func (v BySeverity) Less(i, j int) bool {
	if v[i].PkgName != v[j].PkgName {
		return v[i].PkgName < v[j].PkgName
	} else if v[i].InstalledVersion != v[j].InstalledVersion {
		return v[i].InstalledVersion < v[j].InstalledVersion
	}
	ret := types.CompareSeverityString(
		v[j].Severity, v[i].Severity,
	)
	if ret != 0 {
		return ret > 0
	}
	return v[i].VulnerabilityID < v[j].VulnerabilityID
}

// Swap swaps 2 vulnerability
func (v BySeverity) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
