// Copyright 2022 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 config resolves shared configuration for services, and
// provides functions to access this configuration.
package config

import (
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"

	"github.com/google/safehtml/template"
	"golang.org/x/net/context/ctxhttp"
	"golang.org/x/pkgsite-metrics/internal/derrors"
	mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
)

// Config holds configuration information for the worker server.
type Config struct {
	// ProjectID is the Google Cloud ProjectID where the resources live.
	ProjectID string

	// Identifier for the version currently running.
	// We do not use the version ID from Cloud Run (see
	// https://cloud.google.com/run/docs/reference/container-contract).
	// Instead, we use the DOCKER_IMAGE environment variable, set
	// in the Cloud Build deploy file.
	VersionID string

	// LocationID is the location for the GCP project.
	LocationID string

	// ServiceID names the Cloud Run service.
	ServiceID string

	// StaticPath is the directory containing static files.
	StaticPath template.TrustedSource

	// ServiceAccount is the email of the service account that this process
	// is running as when on GCP.
	ServiceAccount string

	// UseErrorReporting determines whether errors go to the Error Reporting API.
	UseErrorReporting bool

	// BigQuery dataset to write results to.
	BigQueryDataset string

	// QueueName is the name of the Cloud Tasks queue.
	QueueName string

	// QueueURL is the URL that the Cloud Tasks queue should send requests to.
	// It should be used when the worker is not on AppEngine.
	QueueURL string

	// LocalQueueWorkers is the number of concurrent requests to the fetch service, when running locally.
	LocalQueueWorkers int

	// MonitoredResource represents the resource that is running the current binary.
	// It might be a Google AppEngine app, a Cloud Run service, or a Kubernetes pod.
	// See https://cloud.google.com/monitoring/api/resources for more
	// details:
	// "An object representing a resource that can be used for monitoring, logging,
	// billing, or other purposes. Examples include virtual machine instances,
	// databases, and storage devices such as disks.""
	MonitoredResource *mrpb.MonitoredResource

	// DevMode indicates whether the server is running in development mode.
	DevMode bool

	// VulnDBBucketProjectID is the project ID for the vuln DB bucket and its
	// associated load balancer.
	VulnDBBucketProjectID string

	// BinaryBucket holds binaries for govulncheck scanning.
	BinaryBucket string

	// The host, port and user of the pkgsite database used to find
	// modules to scan.
	PkgsiteDBHost string
	PkgsiteDBPort string
	PkgsiteDBName string
	PkgsiteDBUser string
	// The name of the Secret Manager secret holding the DB password.
	PkgsiteDBSecret string

	// Run analysis binaries without sandbox.
	Insecure bool

	// ProxyURL is the url for the Go module proxy.
	ProxyURL string

	// VulnDBURL is the url for the Go vulnerability database.
	VulnDBURL string
}

// Init resolves all configuration values provided by the config package. It
// must be called before any configuration values are used.
func Init(ctx context.Context) (_ *Config, err error) {
	defer derrors.Wrap(&err, "config.Init(ctx)")
	// Build a Config from the execution environment, loading some values
	// from environment variables.

	var ts template.TrustedSource
	if f := flag.Lookup("static"); f != nil {
		ts = template.TrustedSourceFromFlag(f.Value)
	}
	cfg := &Config{
		ProjectID:             os.Getenv("GOOGLE_CLOUD_PROJECT"),
		ServiceID:             os.Getenv("GO_ECOSYSTEM_SERVICE_ID"),
		VersionID:             os.Getenv("DOCKER_IMAGE"),
		LocationID:            "us-central1",
		StaticPath:            ts,
		BigQueryDataset:       GetEnv("GO_ECOSYSTEM_BIGQUERY_DATASET", "disable"),
		QueueName:             os.Getenv("GO_ECOSYSTEM_QUEUE_NAME"),
		QueueURL:              os.Getenv("GO_ECOSYSTEM_QUEUE_URL"),
		VulnDBBucketProjectID: os.Getenv("GO_ECOSYSTEM_VULNDB_BUCKET_PROJECT"),
		BinaryBucket:          os.Getenv("GO_ECOSYSTEM_BINARY_BUCKET"),
		PkgsiteDBHost:         GetEnv("GO_ECOSYSTEM_PKGSITE_DB_HOST", "localhost"),
		PkgsiteDBPort:         GetEnv("GO_ECOSYSTEM_PKGSITE_DB_PORT", "5432"),
		PkgsiteDBName:         GetEnv("GO_ECOSYSTEM_PKGSITE_DB_NAME", "discovery-db"),
		PkgsiteDBUser:         GetEnv("GO_ECOSYSTEM_PKGSITE_DB_USER", "postgres"),
		PkgsiteDBSecret:       os.Getenv("GO_ECOSYSTEM_PKGSITE_DB_SECRET"),
		ProxyURL:              GetEnv("GO_MODULE_PROXY_URL", "https://proxy.golang.org"),
		VulnDBURL:             GetEnv("GO_VULNDB_URL", "https://vuln.go.dev"),
	}
	if OnCloudRun() {
		sa, err := gceMetadata(ctx, "instance/service-accounts/default/email")
		if err != nil {
			return nil, err
		}
		cfg.ServiceAccount = sa
		cfg.MonitoredResource = &mrpb.MonitoredResource{
			Type: "cloud_run_revision",
			Labels: map[string]string{
				"project_id":         cfg.ProjectID,
				"service_name":       cfg.ServiceID,
				"revision_name":      cfg.VersionID,
				"configuration_name": os.Getenv("K_CONFIGURATION"),
			},
		}
		cfg.UseErrorReporting = true
	} else { // running locally, perhaps
		cfg.MonitoredResource = &mrpb.MonitoredResource{
			Type:   "global",
			Labels: map[string]string{"project_id": cfg.ProjectID},
		}
	}
	return cfg, nil
}

// OnCloudRun reports whether the current process is running on Cloud Run.
func OnCloudRun() bool {
	// Use the presence of the environment variables provided by Cloud Run.
	// See https://cloud.google.com/run/docs/reference/container-contract.
	for _, ev := range []string{"K_SERVICE", "K_REVISION", "K_CONFIGURATION"} {
		if os.Getenv(ev) == "" {
			return false
		}
	}
	return true
}

func (c *Config) Validate() error {
	if c.ProjectID == "" {
		return errors.New("missing project")
	}
	if c.BigQueryDataset == "" {
		return errors.New("missing dataset")
	}
	return nil
}

// Dump outputs the current config information to the given Writer.
func (c *Config) Dump(w io.Writer) error {
	fmt.Fprint(w, "config: ")
	enc := json.NewEncoder(w)
	enc.SetIndent("", "    ")
	return enc.Encode(c)
}

// GetEnv looks up the given key from the environment, returning its value if
// it exists, and otherwise returning the given fallback value.
func GetEnv(key, fallback string) string {
	if value, ok := os.LookupEnv(key); ok {
		return value
	}
	return fallback
}

// GetEnvInt performs GetEnv(key, fallback) and parses the
// result as int. If parsing fails, returns errVal.
func GetEnvInt(key, fallback string, errVal int) int {
	v := GetEnv(key, fallback)
	i, err := strconv.Atoi(v)
	if err != nil {
		return errVal
	}
	return i
}

// gceMetadata reads a metadata value from GCE.
// For the possible values of name, see
// https://cloud.google.com/appengine/docs/standard/java/accessing-instance-metadata.
func gceMetadata(ctx context.Context, name string) (_ string, err error) {
	// See https://cloud.google.com/appengine/docs/standard/java/accessing-instance-metadata.
	// (This documentation doesn't exist for Golang, but it seems to work).
	defer derrors.Wrap(&err, "gceMetadata(ctx, %q)", name)

	const metadataURL = "http://metadata.google.internal/computeMetadata/v1/"
	req, err := http.NewRequest("GET", metadataURL+name, nil)
	if err != nil {
		return "", fmt.Errorf("http.NewRequest: %v", err)
	}
	req.Header.Set("Metadata-Flavor", "Google")
	resp, err := ctxhttp.Do(ctx, nil, req)
	if err != nil {
		return "", fmt.Errorf("ctxhttp.Do: %v", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("bad status: %s", resp.Status)
	}
	bytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("io.ReadAll: %v", err)
	}
	return string(bytes), nil
}
