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

import (
	"fmt"
	"sort"
	"strings"

	"golang.org/x/pkgsite/internal"
)

// Symbol is an element in the package API. A symbol can be a constant,
// variable, function, type, field or method.
type Symbol struct {
	// Name is name of the symbol. At a given package version, name must be
	// unique.
	Name string

	// Synopsis is the one line description of the symbol that is displayed.
	Synopsis string

	// Link is the link to the symbol name on pkg.go.dev.
	Link string

	// Section is the section that a symbol appears in.
	Section internal.SymbolSection

	// Kind is the type of a symbol, which is either a constant, variable,
	// function, type, field or method.
	Kind internal.SymbolKind

	// Children contain the child symbols for this symbol. This will
	// only be populated when the SymbolType is "Type". For example, the
	// children of net/http.Handler are FileServer, NotFoundHandler,
	// RedirectHandler, StripPrefix, and TimeoutHandler. Each child
	// symbol will have ParentName set to the Name of this type.
	Children []*Symbol

	// Builds lists all of the build contexts supported by the symbol, it is
	// only available for limited set of builds. If the symbol supports all
	// build contexts, Builds will be nil.
	Builds []string

	// New indicates that the symbol is new as of the version where it is
	// present. For example, if type Client was introduced in v1.0.0 and
	// Client.Timeout was introduced in v1.1.0, New will be false for Client
	// and true for Client.Timeout if this Symbol corresponds to v1.1.0.
	New bool
}

// symbolsForVersions returns an array of symbols for use in the VersionSummary
// of the specified version.
func symbolsForVersion(pkgURLPath string, symbolsAtVersion map[string]*internal.UnitSymbol) [][]*Symbol {
	nameToSymbol := map[string]*Symbol{}
	for _, us := range symbolsAtVersion {
		s, ok := nameToSymbol[us.Name]
		if !ok {
			s = &Symbol{
				Name:     us.Name,
				Synopsis: us.Synopsis,
				Link:     symbolLink(pkgURLPath, us.Name),
				Section:  us.Section,
				Kind:     us.Kind,
				New:      true,
				Builds:   symbolBuilds(us),
			}
		} else if !s.New && us.Kind == internal.SymbolKindType {
			// It's possible that a symbol was already created if this is a parent
			// symbol and we called addSymbol on the child symbol first. In that
			// case, a parent symbol would have been created where s.New is set to
			// false and s.Synopsis is set to the one created in createParent.
			// Update those fields instead of overwritting the struct, since the
			// struct's Children field would have already been populated.
			s.New = true
			s.Synopsis = us.Synopsis
		}
		if us.ParentName == us.Name {
			// s is not a child symbol of a type, so add it to the map and
			// continue.
			nameToSymbol[us.Name] = s
			continue
		}

		// s is a child symbol of a parent type, so append it to the Children field
		// of the parent type.
		parent, ok := nameToSymbol[us.ParentName]
		if !ok {
			parent = createParent(us, pkgURLPath)
			nameToSymbol[us.ParentName] = parent
		}
		if len(parent.Builds) == len(s.Builds) {
			s.Builds = nil
		}
		parent.Children = append(parent.Children, s)
	}
	return sortSymbols(nameToSymbol)
}

func symbolLink(pkgURLPath, name string) string {
	return fmt.Sprintf("%s#%s", pkgURLPath, name)
}

func symbolBuilds(us *internal.UnitSymbol) []string {
	if us.InAll() {
		return nil
	}
	var builds []string
	for _, b := range us.BuildContexts() {
		builds = append(builds, b.String())
	}
	sort.Strings(builds)
	return builds
}

// createParent creates a parent symbol for the provided unit symbol. This is
// used when us is a child of a symbol that may have been introduced at a
// different version. The symbol created will have New set to false, since this
// function is only used when a parent symbol is not found for the unit symbol,
// which means it was not introduced at the same version.
func createParent(us *internal.UnitSymbol, pkgURLPath string) *Symbol {
	s := &Symbol{
		Name:     us.ParentName,
		Synopsis: fmt.Sprintf("type %s", us.ParentName),
		Link:     symbolLink(pkgURLPath, us.ParentName),
		Section:  internal.SymbolSectionTypes,
		Kind:     internal.SymbolKindType,
		Builds:   symbolBuilds(us),
	}
	return s
}

// sortSymbols returns an array of symbols in order of
// (1) Constants (2) Variables (3) Functions and (4) Types.
// Within each section, symbols are sorted alphabetically by name.
// In the types sections, aside from interfaces, child symbols are sorted in
// order of (1) Fields (2) Constants (3) Variables (4) Functions and (5)
// Methods. For interfaces, child symbols are sorted in order of
// (1) Methods (2) Constants (3) Variables and (4) Functions.
func sortSymbols(nameToSymbol map[string]*Symbol) [][]*Symbol {
	sm := map[internal.SymbolSection][]*Symbol{}
	for _, parent := range nameToSymbol {
		sm[parent.Section] = append(sm[parent.Section], parent)

		cm := map[internal.SymbolKind][]*Symbol{}
		parent.Synopsis = strings.TrimSuffix(parent.Synopsis, "{ ... }")
		for _, c := range parent.Children {
			cm[c.Kind] = append(cm[c.Kind], c)
		}
		for _, syms := range cm {
			sortSymbolsGroup(syms)
		}
		symbols := append(append(append(
			cm[internal.SymbolKindField],
			cm[internal.SymbolKindConstant]...),
			cm[internal.SymbolKindVariable]...),
			cm[internal.SymbolKindFunction]...)
		if strings.Contains(parent.Synopsis, "interface") {
			parent.Children = append(cm[internal.SymbolKindMethod], symbols...)
		} else {
			parent.Children = append(symbols, cm[internal.SymbolKindMethod]...)
		}
	}
	for _, syms := range sm {
		sortSymbolsGroup(syms)
	}

	var out [][]*Symbol
	for _, section := range []internal.SymbolSection{
		internal.SymbolSectionConstants,
		internal.SymbolSectionVariables,
		internal.SymbolSectionFunctions,
		internal.SymbolSectionTypes} {
		if sm[section] != nil {
			out = append(out, sm[section])
		}
	}
	return out
}

func sortSymbolsGroup(syms []*Symbol) {
	sort.Slice(syms, func(i, j int) bool {
		return syms[i].Synopsis < syms[j].Synopsis
	})
	for _, s := range syms {
		sort.Strings(s.Builds)
	}
}
