// Copyright 2020 The Go Authors. All rights reserved.
// Licensed under the MIT License.
// See LICENSE in the project root for license information.

package goplssetting

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"sort"
	"strconv"
	"strings"
)

// Generate reads package.json and updates the gopls settings section
// based on `gopls api-json` output. This function requires `jq` to
// manipulate package.json.
func Generate(inputFile string, skipCleanup bool) ([]byte, error) {
	if _, err := os.Stat(inputFile); err != nil {
		return nil, err
	}

	if _, err := exec.LookPath("jq"); err != nil {
		return nil, fmt.Errorf("missing `jq`: %w", err)
	}

	workDir, err := ioutil.TempDir("", "goplssettings")
	if err != nil {
		return nil, err
	}
	log.Printf("WORK=%v", workDir)

	if !skipCleanup {
		defer os.RemoveAll(workDir)
	}

	api, err := readGoplsAPI()
	if err != nil {
		return nil, err
	}
	options, err := extractOptions(api)
	if err != nil {
		return nil, err
	}
	b, err := asVSCodeSettings(options)
	if err != nil {
		return nil, err
	}
	f, err := ioutil.TempFile(workDir, "gopls.settings")
	if err != nil {
		return nil, err
	}
	if _, err := f.Write(b); err != nil {
		return nil, err
	}
	if err := f.Close(); err != nil {
		return nil, err
	}

	return rewritePackageJSON(f.Name(), inputFile)
}

// readGoplsAPI returns the output of `gopls api-json`.
func readGoplsAPI() (*APIJSON, error) {
	version, err := exec.Command("gopls", "-v", "version").Output()
	if err != nil {
		return nil, fmt.Errorf("failed to check gopls version: %v", err)
	}
	log.Printf("Reading settings of gopls....\nversion:\n%s\n", version)

	out, err := exec.Command("gopls", "api-json").Output()
	if err != nil {
		return nil, fmt.Errorf("failed to run gopls: %v", err)
	}

	api := &APIJSON{}
	if err := json.Unmarshal(out, api); err != nil {
		return nil, fmt.Errorf("failed to unmarshal: %v", err)
	}
	return api, nil
}

// extractOptions extracts the options from APIJSON.
// It may rearrange the ordering and documentation for better presentation.
func extractOptions(api *APIJSON) ([]*OptionJSON, error) {
	type sortableOptionJSON struct {
		*OptionJSON
		section string
	}
	options := []sortableOptionJSON{}
	for k, v := range api.Options {
		for _, o := range v {
			options = append(options, sortableOptionJSON{OptionJSON: o, section: k})
		}
	}
	sort.SliceStable(options, func(i, j int) bool {
		pi := priority(options[i].OptionJSON)
		pj := priority(options[j].OptionJSON)
		if pi == pj {
			return options[i].Name < options[j].Name
		}
		return pi < pj
	})

	opts := []*OptionJSON{}
	for _, v := range options {
		if name := statusName(v.OptionJSON); name != "" {
			v.OptionJSON.Doc = name + " " + v.OptionJSON.Doc
		}
		opts = append(opts, v.OptionJSON)
	}
	return opts, nil
}

func priority(opt *OptionJSON) int {
	switch toStatus(opt.Status) {
	case Experimental:
		return 10
	case Debug:
		return 100
	}
	return 1000
}

func statusName(opt *OptionJSON) string {
	switch toStatus(opt.Status) {
	case Experimental:
		return "(Experimental)"
	case Advanced:
		return "(Advanced)"
	case Debug:
		return "(For Debugging)"
	}
	return ""
}

func toStatus(s string) Status {
	switch s {
	case "experimental":
		return Experimental
	case "debug":
		return Debug
	case "advanced":
		return Advanced
	case "":
		return None
	default:
		panic(fmt.Sprintf("unexpected status: %s", s))
	}
}

// rewritePackageJSON rewrites the input package.json by running `jq`
// to update all existing gopls settings with the ones from the newSettings
// file.
func rewritePackageJSON(newSettings, inFile string) ([]byte, error) {
	prog := `.contributes.configuration.properties+=$GOPLS_SETTINGS[0]`
	cmd := exec.Command("jq", "--slurpfile", "GOPLS_SETTINGS", newSettings, prog, inFile)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("jq run failed (%v): %s", err, &stderr)
	}
	return bytes.TrimSpace(stdout.Bytes()), nil
}

// asVSCodeSettings converts the given options to match the VS Code settings
// format.
func asVSCodeSettings(options []*OptionJSON) ([]byte, error) {
	seen := map[string][]*OptionJSON{}
	for _, opt := range options {
		seen[opt.Hierarchy] = append(seen[opt.Hierarchy], opt)
	}
	for _, v := range seen {
		sort.Slice(v, func(i, j int) bool {
			return v[i].Name < v[j].Name
		})
	}
	goplsProperties, goProperties, err := collectProperties(seen)
	if err != nil {
		return nil, err
	}
	goProperties["gopls"] = &Object{
		Type:                 "object",
		MarkdownDescription:  "Configure the default Go language server ('gopls'). In most cases, configuring this section is unnecessary. See [the documentation](https://github.com/golang/tools/blob/master/gopls/doc/settings.md) for all available settings.",
		Scope:                "resource",
		AdditionalProperties: false,
		Properties:           goplsProperties,
	}
	return json.Marshal(goProperties)
}

func collectProperties(m map[string][]*OptionJSON) (goplsProperties, goProperties map[string]*Object, err error) {
	var sorted []string
	var containsEmpty bool
	for k := range m {
		if k == "" {
			containsEmpty = true
			continue
		}
		sorted = append(sorted, k)
	}
	sort.Strings(sorted)
	if containsEmpty {
		sorted = append(sorted, "")
	}
	goplsProperties, goProperties = map[string]*Object{}, map[string]*Object{}
	for _, hierarchy := range sorted {
		if hierarchy == "ui.inlayhint" {
			for _, opt := range m[hierarchy] {
				for _, k := range opt.EnumKeys.Keys {
					unquotedName, err := strconv.Unquote(k.Name)
					if err != nil {
						return nil, nil, err
					}
					key := "go.inlayHints." + unquotedName
					goProperties[key] = &Object{
						MarkdownDescription: k.Doc,
						Type:                "boolean",
						Default:             formatDefault(k.Default, "boolean"),
					}
				}
			}
			continue
		}
		for _, opt := range m[hierarchy] {
			obj, err := toObject(opt)
			if err != nil {
				return nil, nil, err
			}
			// TODO(hyangah): move diagnostic to all go.diagnostic.
			if hierarchy == "ui.diagnostic" && opt.Name == "vulncheck" {
				goProperties["go.diagnostic.vulncheck"] = obj
				continue
			}
			key := opt.Name
			if hierarchy != "" {
				key = hierarchy + "." + key
			}
			goplsProperties[key] = obj
		}
	}
	return goplsProperties, goProperties, nil
}

func toObject(opt *OptionJSON) (*Object, error) {
	doc := opt.Doc
	if mappedTo, ok := associatedToExtensionProperties[opt.Name]; ok {
		doc = fmt.Sprintf("%v\nIf unspecified, values of `%v` will be propagated.\n", doc, strings.Join(mappedTo, ", "))
	}
	obj := &Object{
		MarkdownDescription: doc,
		// TODO: are all gopls settings in the resource scope?
		Scope: "resource",
		// TODO: consider 'additionalProperties' if gopls api-json
		// outputs acceptable properties.
		// TODO: deprecation attribute
	}
	// Handle any enum types.
	if opt.Type == "enum" {
		for _, v := range opt.EnumValues {
			unquotedName, err := strconv.Unquote(v.Value)
			if err != nil {
				return nil, err
			}
			obj.Enum = append(obj.Enum, unquotedName)
			obj.MarkdownEnumDescriptions = append(obj.MarkdownEnumDescriptions, v.Doc)
		}
	}
	// Handle any objects whose keys are enums.
	if len(opt.EnumKeys.Keys) > 0 {
		if obj.Properties == nil {
			obj.Properties = map[string]*Object{}
		}
		for _, k := range opt.EnumKeys.Keys {
			unquotedName, err := strconv.Unquote(k.Name)
			if err != nil {
				return nil, err
			}
			obj.Properties[unquotedName] = &Object{
				Type:                propertyType(opt.EnumKeys.ValueType),
				MarkdownDescription: k.Doc,
				Default:             formatDefault(k.Default, opt.EnumKeys.ValueType),
			}
		}
	}
	obj.Type = propertyType(opt.Type)
	obj.Default = formatOptionDefault(opt)

	return obj, nil
}

func formatOptionDefault(opt *OptionJSON) interface{} {
	// Each key will have its own default value, instead of one large global
	// one. (Alternatively, we can build the default from the keys.)
	if len(opt.EnumKeys.Keys) > 0 {
		return nil
	}

	return formatDefault(opt.Default, opt.Type)
}

// formatDefault converts a string-based default value to an actual value that
// can be marshaled to JSON. Right now, gopls generates default values as
// strings, but perhaps that will change.
func formatDefault(def, typ string) interface{} {
	switch typ {
	case "enum", "string", "time.Duration":
		unquote, err := strconv.Unquote(def)
		if err == nil {
			def = unquote
		}
	case "[]string":
		var x []string
		if err := json.Unmarshal([]byte(def), &x); err == nil {
			return x
		}
	}
	switch def {
	case "{}", "[]":
		return nil
	case "true":
		return true
	case "false":
		return false
	default:
		return def
	}
}

var associatedToExtensionProperties = map[string][]string{
	"buildFlags": {"go.buildFlags", "go.buildTags"},
}

func propertyType(t string) string {
	switch t {
	case "string":
		return "string"
	case "bool":
		return "boolean"
	case "enum":
		return "string"
	case "time.Duration":
		return "string"
	case "[]string":
		return "array"
	case "map[string]string", "map[string]bool":
		return "object"
	}
	log.Fatalf("unknown type %q", t)
	return ""
}

func check(err error) {
	if err == nil {
		return
	}

	log.Output(1, err.Error())
	os.Exit(1)
}

// Object represents a VS Code settings object.
type Object struct {
	Type                     string             `json:"type,omitempty"`
	MarkdownDescription      string             `json:"markdownDescription,omitempty"`
	AdditionalProperties     bool               `json:"additionalProperties,omitempty"`
	Enum                     []string           `json:"enum,omitempty"`
	MarkdownEnumDescriptions []string           `json:"markdownEnumDescriptions,omitempty"`
	Default                  interface{}        `json:"default,omitempty"`
	Scope                    string             `json:"scope,omitempty"`
	Properties               map[string]*Object `json:"properties,omitempty"`
}

type Status int

const (
	Experimental = Status(iota)
	Debug
	Advanced
	None
)

// APIJSON is the output json type of `gopls api-json`.
// Types copied from golang.org/x/tools/internal/lsp/source/options.go.
type APIJSON struct {
	Options   map[string][]*OptionJSON
	Commands  []*CommandJSON
	Lenses    []*LensJSON
	Analyzers []*AnalyzerJSON
}

type OptionJSON struct {
	Name       string
	Type       string
	Doc        string
	EnumKeys   EnumKeys
	EnumValues []EnumValue
	Default    string
	Status     string
	Hierarchy  string
}

type EnumKeys struct {
	ValueType string
	Keys      []EnumKey
}

type EnumKey struct {
	Name    string
	Doc     string
	Default string
}

type EnumValue struct {
	Value string
	Doc   string
}

type CommandJSON struct {
	Command string
	Title   string
	Doc     string
}

type LensJSON struct {
	Lens  string
	Title string
	Doc   string
}

type AnalyzerJSON struct {
	Name    string
	Doc     string
	Default bool
}
