// 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

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 vulncheck 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:             "go-ecosystem-worker",
		VersionID:             os.Getenv("DOCKER_IMAGE"),
		LocationID:            "us-central1",
		StaticPath:            ts,
		BigQueryDataset:       GetEnv("GO_ECOSYSTEM_BIGQUERY_DATASET", "test"),
		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
}
