// Copyright 2021 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 audit

import (
	"go/build"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/packages"
	"golang.org/x/vuln/client"
)

// FetchVulnerabilities fetches vulnerabilities that affect the supplied modules.
func FetchVulnerabilities(client client.Client, modules []*packages.Module) (ModuleVulnerabilities, error) {
	mv := ModuleVulnerabilities{}
	for _, mod := range modules {
		modPath := mod.Path
		if mod.Replace != nil {
			modPath = mod.Replace.Path
		}

		// skip loading vulns for local imports
		if isLocal(mod) {
			// TODO: what if client has its own db
			// with local vulns?
			continue
		}
		vulns, err := client.GetByModule(modPath)
		if err != nil {
			return nil, err
		}
		if len(vulns) == 0 {
			continue
		}
		mv = append(mv, modVulns{
			mod:   mod,
			vulns: vulns,
		})
	}
	return mv, nil
}

func isLocal(mod *packages.Module) bool {
	modDir := mod.Dir
	if mod.Replace != nil {
		modDir = mod.Replace.Dir
	}
	return modDir != "" && !strings.HasPrefix(modDir, modCacheDirectory())
}

func modCacheDirectory() string {
	var modCacheDir string
	// TODO: define modCacheDir using cmd/go/internal/cfg.GOMODCACHE
	if modCacheDir = os.Getenv("GOMODCACHE"); modCacheDir == "" {
		if modCacheDir = os.Getenv("GOPATH"); modCacheDir == "" {
			modCacheDir = build.Default.GOPATH
		}
		modCacheDir = filepath.Join(modCacheDir, "pkg", "mod")
	}
	return modCacheDir
}
