// Copyright 2020 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.

// Command genapijson generates JSON describing gopls' external-facing API,
// including user settings and commands.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"os"
	"reflect"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/lsp/mod"
	"golang.org/x/tools/internal/lsp/source"
)

var (
	output = flag.String("output", "", "output file")
)

func main() {
	flag.Parse()
	if err := doMain(); err != nil {
		fmt.Fprintf(os.Stderr, "Generation failed: %v\n", err)
		os.Exit(1)
	}
}

func doMain() error {
	out := os.Stdout
	if *output != "" {
		var err error
		out, err = os.OpenFile(*output, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
		if err != nil {
			return err
		}
		defer out.Close()
	}

	content, err := generate()
	if err != nil {
		return err
	}
	if _, err := out.Write(content); err != nil {
		return err
	}

	return out.Close()
}

func generate() ([]byte, error) {
	pkgs, err := packages.Load(
		&packages.Config{
			Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedDeps,
		},
		"golang.org/x/tools/internal/lsp/source",
	)
	if err != nil {
		return nil, err
	}
	pkg := pkgs[0]

	api := &source.APIJSON{
		Options: map[string][]*source.OptionJSON{},
	}
	defaults := source.DefaultOptions()
	for _, cat := range []reflect.Value{
		reflect.ValueOf(defaults.DebuggingOptions),
		reflect.ValueOf(defaults.UserOptions),
		reflect.ValueOf(defaults.ExperimentalOptions),
	} {
		opts, err := loadOptions(cat, pkg)
		if err != nil {
			return nil, err
		}
		catName := strings.TrimSuffix(cat.Type().Name(), "Options")
		api.Options[catName] = opts
	}

	api.Commands, err = loadCommands(pkg)
	if err != nil {
		return nil, err
	}
	api.Lenses = loadLenses(api.Commands)
	marshaled, err := json.Marshal(api)
	if err != nil {
		return nil, err
	}
	buf := bytes.NewBuffer(nil)
	fmt.Fprintf(buf, "// Code generated by \"golang.org/x/tools/internal/lsp/source/genapijson\"; DO NOT EDIT.\n\npackage source\n\nconst GeneratedAPIJSON = %q\n", string(marshaled))
	return buf.Bytes(), nil
}

func loadOptions(category reflect.Value, pkg *packages.Package) ([]*source.OptionJSON, error) {
	// Find the type information and ast.File corresponding to the category.
	optsType := pkg.Types.Scope().Lookup(category.Type().Name())
	if optsType == nil {
		return nil, fmt.Errorf("could not find %v in scope %v", category.Type().Name(), pkg.Types.Scope())
	}

	file, err := fileForPos(pkg, optsType.Pos())
	if err != nil {
		return nil, err
	}

	enums := loadEnums(pkg)

	var opts []*source.OptionJSON
	optsStruct := optsType.Type().Underlying().(*types.Struct)
	for i := 0; i < optsStruct.NumFields(); i++ {
		// The types field gives us the type.
		typesField := optsStruct.Field(i)
		path, _ := astutil.PathEnclosingInterval(file, typesField.Pos(), typesField.Pos())
		if len(path) < 2 {
			return nil, fmt.Errorf("could not find AST node for field %v", typesField)
		}
		// The AST field gives us the doc.
		astField, ok := path[1].(*ast.Field)
		if !ok {
			return nil, fmt.Errorf("unexpected AST path %v", path)
		}

		// The reflect field gives us the default value.
		reflectField := category.FieldByName(typesField.Name())
		if !reflectField.IsValid() {
			return nil, fmt.Errorf("could not find reflect field for %v", typesField.Name())
		}

		// Format the default value. VSCode exposes settings as JSON, so showing them as JSON is reasonable.
		// Nil values format as "null" so print them as hardcoded empty values.
		def := reflectField.Interface()
		defBytes, err := json.Marshal(def)
		if err != nil {
			return nil, err
		}

		switch reflectField.Type().Kind() {
		case reflect.Map:
			if reflectField.IsNil() {
				defBytes = []byte("{}")
			}
		case reflect.Slice:
			if reflectField.IsNil() {
				defBytes = []byte("[]")
			}
		}

		typ := typesField.Type().String()
		if _, ok := enums[typesField.Type()]; ok {
			typ = "enum"
		}

		opts = append(opts, &source.OptionJSON{
			Name:       lowerFirst(typesField.Name()),
			Type:       typ,
			Doc:        lowerFirst(astField.Doc.Text()),
			Default:    string(defBytes),
			EnumValues: enums[typesField.Type()],
		})
	}
	return opts, nil
}

func loadEnums(pkg *packages.Package) map[types.Type][]string {
	enums := map[types.Type][]string{}
	for _, name := range pkg.Types.Scope().Names() {
		obj := pkg.Types.Scope().Lookup(name)
		cnst, ok := obj.(*types.Const)
		if !ok {
			continue
		}
		enums[obj.Type()] = append(enums[obj.Type()], cnst.Val().ExactString())
	}
	return enums
}

func loadCommands(pkg *packages.Package) ([]*source.CommandJSON, error) {
	// The code that defines commands is much more complicated than the
	// code that defines options, so reading comments for the Doc is very
	// fragile. If this causes problems, we should switch to a dynamic
	// approach and put the doc in the Commands struct rather than reading
	// from the source code.

	// Find the Commands slice.
	typesSlice := pkg.Types.Scope().Lookup("Commands")
	f, err := fileForPos(pkg, typesSlice.Pos())
	if err != nil {
		return nil, err
	}
	path, _ := astutil.PathEnclosingInterval(f, typesSlice.Pos(), typesSlice.Pos())
	vspec := path[1].(*ast.ValueSpec)
	var astSlice *ast.CompositeLit
	for i, name := range vspec.Names {
		if name.Name == "Commands" {
			astSlice = vspec.Values[i].(*ast.CompositeLit)
		}
	}

	var commands []*source.CommandJSON

	// Parse the objects it contains.
	for _, elt := range astSlice.Elts {
		// Find the composite literal of the Command.
		typesCommand := pkg.TypesInfo.ObjectOf(elt.(*ast.Ident))
		path, _ := astutil.PathEnclosingInterval(f, typesCommand.Pos(), typesCommand.Pos())
		vspec := path[1].(*ast.ValueSpec)

		var astCommand ast.Expr
		for i, name := range vspec.Names {
			if name.Name == typesCommand.Name() {
				astCommand = vspec.Values[i]
			}
		}

		// Read the Name and Title fields of the literal.
		var name, title string
		ast.Inspect(astCommand, func(n ast.Node) bool {
			kv, ok := n.(*ast.KeyValueExpr)
			if ok {
				k := kv.Key.(*ast.Ident).Name
				switch k {
				case "Name":
					name = strings.Trim(kv.Value.(*ast.BasicLit).Value, `"`)
				case "Title":
					title = strings.Trim(kv.Value.(*ast.BasicLit).Value, `"`)
				}
			}
			return true
		})

		if title == "" {
			title = name
		}

		// Conventionally, the doc starts with the name of the variable.
		// Replace it with the name of the command.
		doc := vspec.Doc.Text()
		doc = strings.Replace(doc, typesCommand.Name(), name, 1)

		commands = append(commands, &source.CommandJSON{
			Command: name,
			Title:   title,
			Doc:     doc,
		})
	}
	return commands, nil
}

func loadLenses(commands []*source.CommandJSON) []*source.LensJSON {
	lensNames := map[string]struct{}{}
	for k := range source.LensFuncs() {
		lensNames[k] = struct{}{}
	}
	for k := range mod.LensFuncs() {
		lensNames[k] = struct{}{}
	}

	var lenses []*source.LensJSON

	for _, cmd := range commands {
		if _, ok := lensNames[cmd.Command]; ok {
			lenses = append(lenses, &source.LensJSON{
				Lens:  cmd.Command,
				Title: cmd.Title,
				Doc:   cmd.Doc,
			})
		}
	}
	return lenses
}

func lowerFirst(x string) string {
	if x == "" {
		return x
	}
	return strings.ToLower(x[:1]) + x[1:]
}

func fileForPos(pkg *packages.Package, pos token.Pos) (*ast.File, error) {
	fset := pkg.Fset
	for _, f := range pkg.Syntax {
		if fset.Position(f.Pos()).Filename == fset.Position(pos).Filename {
			return f, nil
		}
	}
	return nil, fmt.Errorf("no file for pos %v", pos)
}
