/*
Copyright 2021 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Documentation generator
package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/bazelbuild/buildtools/warn"
	"github.com/golang/protobuf/proto"

	docspb "github.com/bazelbuild/buildtools/warn/docs/proto"
)

func readWarningsFromFile(path string) (*docspb.Warnings, error) {
	content, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}
	warnings := &docspb.Warnings{}
	if err := proto.UnmarshalText(string(content), warnings); err != nil {
		return nil, err
	}
	return warnings, nil
}

func isExistingWarning(name string) bool {
	for _, n := range warn.AllWarnings {
		if n == name {
			return true
		}
	}
	return false
}

func isDisabledWarning(name string) bool {
	if !isExistingWarning(name) {
		return false
	}
	for _, n := range warn.DefaultWarnings {
		if n == name {
			return false
		}
	}
	return true
}

func generateWarningsDocs(warnings *docspb.Warnings) string {
	var b bytes.Buffer

	b.WriteString(`# Buildifier warnings

Warning categories supported by buildifier's linter:

`)

	// Table of contents
	var names []string
	for _, w := range warnings.Warnings {
		names = append(names, w.Name...)
	}
	sort.Strings(names)
	for _, n := range names {
		fmt.Fprintf(&b, "  * [`%s`](#%s)\n", n, n)
	}

	// Misc
	b.WriteString(`
### <a name="suppress"></a>How to disable warnings

All warnings can be disabled / suppressed / ignored by adding a special comment ` + "`" + `# buildifier: disable=<category_name>` + "`" + ` to
the expression that causes the warning. Historically comments with ` + "`" + `buildozer` + "`" + ` instead of
` + "`" + `buildifier` + "`" + ` are also supported, they are equivalent.

#### Examples

` + "```" + `python
# buildifier: disable=no-effect
"""
A multiline comment as a string literal.

Docstrings don't trigger the warning if they are first statements of a file or a function.
"""

if debug:
    print("Debug information:", foo)  # buildifier: disable=print
` + "```\n")

	// Individual warnings
	sort.Slice(warnings.Warnings, func(i, j int) bool {
		return strings.Compare(warnings.Warnings[i].Name[0], warnings.Warnings[j].Name[0]) < 0
	})
	for _, w := range warnings.Warnings {
		// Header
		b.WriteString("\n--------------------------------------------------------------------------------\n\n## ")
		for _, n := range w.Name {
			fmt.Fprintf(&b, "<a name=%q></a>", n)
		}
		fmt.Fprintf(&b, "%s\n\n", w.Header)

		// Name(s)
		if len(w.Name) == 1 {
			fmt.Fprintf(&b, "  * Category name: `%s`\n", w.Name[0])
		} else {
			b.WriteString("  * Category names:\n")
			for _, n := range w.Name {
				fmt.Fprintf(&b, "    * `%s`\n", n)
			}
		}

		// Bazel --incompatible flag
		if w.BazelFlag != "" {
			label := fmt.Sprintf("`%s`", w.BazelFlag)
			if w.BazelFlagLink != "" {
				label = fmt.Sprintf("[%s](%s)", label, w.BazelFlagLink)
			}
			fmt.Fprintf(&b, "  * Flag in Bazel: %s\n", label)
		}

		// Automatic fix
		fix := "no"
		if w.Autofix {
			fix = "yes"
		}
		fmt.Fprintf(&b, "  * Automatic fix: %s\n", fix)

		// Disabled by default
		if isDisabledWarning(w.Name[0]) {
			b.WriteString("  * [Disabled by default](buildifier/README.md#linter)\n")
		}

		// Non-existent
		if !isExistingWarning(w.Name[0]) {
			b.WriteString("  * Not supported by the latest version of Buildifier\n")
		}

		// Suppress the warning
		b.WriteString("  * [Suppress the warning](#suppress): ")
		for i, n := range w.Name {
			if i != 0 {
				b.WriteString(", ")
			}
			fmt.Fprintf(&b, "`# buildifier: disable=%s`", n)
		}
		b.WriteString("\n")

		// Description
		fmt.Fprintf(&b, "\n%s\n", w.Description)
	}
	return b.String()
}

func writeWarningsDocs(docs, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	if _, err := f.WriteString(docs); err != nil {
		return err
	}
	return f.Close()
}

func main() {
	flag.Parse()
	warnings, err := readWarningsFromFile(flag.Arg(0))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	docs := generateWarningsDocs(warnings)
	if err := writeWarningsDocs(docs, flag.Arg(1)); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
