// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package genericosv

import (
	"fmt"
	"sort"
	"strings"

	osvschema "github.com/google/osv-scanner/pkg/models"
	"golang.org/x/exp/slices"
	"golang.org/x/mod/module"
	"golang.org/x/vulndb/internal/cveschema5"
	"golang.org/x/vulndb/internal/ghsa"
	"golang.org/x/vulndb/internal/osv"
	"golang.org/x/vulndb/internal/proxy"
	"golang.org/x/vulndb/internal/report"
	"golang.org/x/vulndb/internal/version"
)

// ToReport converts OSV into a Go Report with the given ID.
func (osv *Entry) ToReport(goID string, pc *proxy.Client) *report.Report {
	r := &report.Report{
		ID:          goID,
		Summary:     osv.Summary,
		Description: osv.Details,
	}
	addNote := func(note string) {
		r.Notes = append(r.Notes, note)
	}
	addAlias := func(alias string) {
		switch {
		case cveschema5.IsCVE(alias):
			r.CVEs = append(r.CVEs, alias)
		case ghsa.IsGHSA(alias):
			r.GHSAs = append(r.GHSAs, alias)
		default:
			addNote(fmt.Sprintf("create: found alias %s that is not a GHSA or CVE", alias))
		}
	}
	addAlias(osv.ID)
	for _, alias := range osv.Aliases {
		addAlias(alias)
	}
	for _, ref := range osv.References {
		r.References = append(r.References, convertRef(ref))
	}
	r.Modules = affectedToModules(osv.Affected, addNote, pc)
	r.Credits = convertCredits(osv.Credits)
	r.Fix(pc)
	if lints := r.Lint(pc); len(lints) > 0 {
		slices.Sort(lints)
		for _, lint := range lints {
			addNote(fmt.Sprintf("lint: %s", lint))
		}
	}
	return r
}

type addNoteFunc func(string)

func affectedToModules(as []osvschema.Affected, addNote addNoteFunc, pc *proxy.Client) []*report.Module {
	var modules []*report.Module
	for _, a := range as {
		if a.Package.Ecosystem != osvschema.EcosystemGo {
			continue
		}

		modules = append(modules, &report.Module{
			Module:   a.Package.Name,
			Versions: convertVersions(a.Ranges, addNote),
		})
	}

	for _, m := range modules {
		extractImportPath(m, pc)
		fixMajorVersion(m, pc)
		canonicalize(m, pc)
		m.FixVersions(pc)
	}

	sortModules(modules)
	return modules
}

// extractImportPath checks if the module m's "module" path is actually
// an import path. If so, it adds the import path to the packages list
// and fixes the module path. Modifies m.
//
// Does nothing if the module path is already correct, or isn't recognized
// by the proxy at all.
func extractImportPath(m *report.Module, pc *proxy.Client) {
	path := m.Module
	modulePath, err := pc.FindModule(m.Module)
	if err != nil || // path doesn't contain a module, needs human review
		path == modulePath { // path is already a module, no action needed
		return
	}
	m.Module = modulePath
	m.Packages = append(m.Packages, &report.Package{Package: path})
}

// fixMajorVersion corrects the major version prefix of the module
// path if possible.
// For now, it gives up if it encounters various problems and
// special cases (see comments inline).
func fixMajorVersion(m *report.Module, pc *proxy.Client) {
	if strings.HasPrefix(m.Module, "gopkg.in/") {
		return // don't attempt to fix gopkg.in modules
	}
	// If there is no "introduced" version, don't attempt to fix
	// major version.
	// Example: example.com/module is fixed at 2.2.2. This likely means
	// that example.com/module is vulnerable at all versions and
	// example.com/module/v2 is vulnerable up to 2.2.2.
	// Changing example.com/module to example.com/module/v2 would lose
	// information.
	hasIntroduced := func(m *report.Module) bool {
		for _, vr := range m.Versions {
			if vr.Introduced != "" {
				return true
			}
		}
		return false
	}
	if !hasIntroduced(m) {
		return
	}
	wantMajor, ok := commonMajor(m.Versions)
	if !ok { // inconsistent major version, don't attempt to fix
		return
	}
	prefix, major, ok := module.SplitPathVersion(m.Module)
	if !ok { // couldn't parse module path, don't attempt to fix
		return
	}
	if major == wantMajor {
		return // nothing to do
	}
	fixed := prefix + wantMajor
	if !pc.ModuleExists(fixed) {
		return // attempted fixed module doesn't exist, give up
	}
	m.Module = fixed
}

// commonMajor returns the major version path suffix (e.g. "/v2") common
// to all versions in the version range, or ("", false) if not all versions
// have the same major version.
// Returns ("", true) if the major version is 0 or 1.
func commonMajor(vs []report.VersionRange) (_ string, ok bool) {
	const (
		v0   = "v0"
		v1   = "v1"
		v0v1 = "v0 or v1"
	)

	getMajor := func(v string) string {
		m := version.Major(v)
		if m == v0 || m == v1 {
			return v0v1
		}
		return m
	}

	major := getMajor(first(vs))
	for _, vr := range vs {
		for _, v := range []string{vr.Introduced, vr.Fixed} {
			if v == "" {
				continue
			}
			current := getMajor(v)
			if current != major {
				return "", false
			}
		}
	}
	if major == v0v1 {
		return "", true
	}
	return "/" + major, true
}

// canonicalize attempts to canonicalize the module path,
// and updates the module path and packages list if successful.
// Modifies m.
//
// Does nothing if the module path is already canonical, or isn't recognized
// by the proxy at all.
func canonicalize(m *report.Module, pc *proxy.Client) {
	if len(m.Versions) == 0 {
		return // no versions, don't attempt to fix
	}

	canonical, err := commonCanonical(m, pc)
	if err != nil {
		return // no consistent canonical version found, don't attempt to fix
	}

	original := m.Module
	m.Module = canonical

	// Fix any package paths.
	for _, p := range m.Packages {
		if strings.HasPrefix(p.Package, original) {
			p.Package = canonical + strings.TrimPrefix(p.Package, original)
		}
	}
}

func commonCanonical(m *report.Module, pc *proxy.Client) (string, error) {
	canonical, err := pc.CanonicalModulePath(m.Module, first(m.Versions))
	if err != nil {
		return "", err
	}

	for _, vr := range m.Versions {
		for _, v := range []string{vr.Introduced, vr.Fixed} {
			if v == "" {
				continue
			}
			current, err := pc.CanonicalModulePath(m.Module, v)
			if err != nil {
				return "", err
			}
			if current != canonical {
				return "", fmt.Errorf("inconsistent canonical module paths: %s and %s", canonical, current)
			}
		}
	}
	return canonical, nil
}

func sortModules(ms []*report.Module) {
	sort.Slice(ms, func(i, j int) bool {
		m1, m2 := ms[i], ms[j]
		// Break ties by lowest affected version, assuming the version list is sorted.
		if m1.Module == m2.Module {
			vr1, vr2 := m1.Versions, m2.Versions
			if len(vr1) == 0 {
				return true
			} else if len(vr2) == 0 {
				return false
			}
			return version.Before(first(vr1), first(vr2))
		}
		return m1.Module < m2.Module
	})
}

func first(vrs []report.VersionRange) string {
	for _, vr := range vrs {
		for _, v := range []string{vr.Introduced, vr.Fixed} {
			if v != "" {
				return v
			}
		}
	}
	return ""
}

func convertVersions(rs []osvschema.Range, addNote addNoteFunc) []report.VersionRange {
	var vrs []report.VersionRange
	for _, r := range rs {
		for _, e := range r.Events {
			var vr report.VersionRange
			switch {
			case e.Introduced == "0":
				continue
			case e.Introduced != "":
				vr.Introduced = e.Introduced
			case e.Fixed != "":
				vr.Fixed = e.Fixed
			default:
				addNote(fmt.Sprintf("create: unsupported version range event %#v", e))
				continue
			}
			vrs = append(vrs, vr)
		}
	}
	return vrs
}

func convertRef(ref osvschema.Reference) *report.Reference {
	return &report.Reference{
		Type: osv.ReferenceType(ref.Type),
		URL:  ref.URL,
	}
}

func convertCredits(cs []osvschema.Credit) []string {
	var credits []string
	for _, c := range cs {
		credit := c.Name
		if len(c.Contact) != 0 {
			credit = fmt.Sprintf("%s (%s)", c.Name, strings.Join(c.Contact, ","))
		}
		credits = append(credits, credit)
	}
	return credits
}
