package recipe

import (
	"strings"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/formatter"
	"coopcloud.tech/abra/pkg/i18n"
	"coopcloud.tech/abra/pkg/lint"
	"coopcloud.tech/abra/pkg/log"
	"github.com/spf13/cobra"
)

// translators: `abra recipe lint` aliases. use a comma separated list of
// aliases with no spaces in between
var recipeLintAliases = i18n.G("l")

var RecipeLintCommand = &cobra.Command{
	// translators: `recipe lint` command
	Use: i18n.G("lint <recipe> [flags]"),
	// translators: Short description for `recipe lint` command
	Short:   i18n.G("Lint a recipe"),
	Aliases: strings.Split(recipeLintAliases, ","),
	Args:    cobra.MinimumNArgs(1),
	ValidArgsFunction: func(
		cmd *cobra.Command,
		args []string,
		toComplete string) ([]string, cobra.ShellCompDirective) {
		return autocomplete.RecipeNameComplete()
	},
	Run: func(cmd *cobra.Command, args []string) {
		recipe := internal.ValidateRecipe(args, cmd.Name())

		if err := recipe.Ensure(internal.GetEnsureContext()); err != nil {
			log.Fatal(err)
		}

		headers := []string{
			i18n.G("ref"),
			i18n.G("rule"),
			i18n.G("severity"),
			i18n.G("satisfied"),
			i18n.G("skipped"),
			i18n.G("resolve"),
		}

		table, err := formatter.CreateTable()
		if err != nil {
			log.Fatal(err)
		}

		table.Headers(headers...)

		hasError := false
		var rows [][]string
		var warnMessages []string
		for level := range lint.LintRules {
			for _, rule := range lint.LintRules[level] {
				if onlyError && rule.Level != "error" {
					log.Debug(i18n.G("skipping %s, does not have level \"error\"", rule.Ref))
					continue
				}

				skipped := false
				if rule.Skip(recipe) {
					skipped = true
				}

				skippedOutput := "-"
				if skipped {
					skippedOutput = "✅"
				}

				satisfied := false
				if !skipped {
					ok, err := rule.Function(recipe)
					if err != nil {
						warnMessages = append(warnMessages, err.Error())
					}

					if !ok && rule.Level == i18n.G("error") {
						hasError = true
					}

					if ok {
						satisfied = true
					}
				}

				satisfiedOutput := "✅"
				if !satisfied {
					satisfiedOutput = "❌"
					if skipped {
						satisfiedOutput = "-"
					}
				}

				row := []string{
					rule.Ref,
					rule.Description,
					rule.Level,
					satisfiedOutput,
					skippedOutput,
					rule.HowToResolve,
				}

				rows = append(rows, row)
				table.Row(row...)
			}
		}

		if len(rows) > 0 {
			if err := formatter.PrintTable(table); err != nil {
				log.Fatal(err)
			}

			for _, warnMsg := range warnMessages {
				log.Warn(warnMsg)
			}

			if hasError {
				log.Warn(i18n.G("critical errors present in %s config", recipe.Name))
			}
		}
	},
}

var (
	onlyError bool
)

func init() {
	RecipeLintCommand.Flags().BoolVarP(
		&internal.Chaos,
		i18n.G("chaos"),
		i18n.G("C"),
		false,
		i18n.G("ignore uncommitted recipes changes"),
	)

	RecipeLintCommand.Flags().BoolVarP(
		&onlyError,
		i18n.G("error"),
		i18n.G("e"),
		false,
		i18n.G("only show errors"),
	)
}
