package recipe

import (
	"context"
	"fmt"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/formatter"
	"coopcloud.tech/abra/pkg/lint"
	"coopcloud.tech/abra/pkg/log"
	"github.com/urfave/cli/v3"
)

var recipeLintCommand = cli.Command{
	Name:      "lint",
	Usage:     "Lint a recipe",
	Aliases:   []string{"l"},
	UsageText: "abra recipe lint <recipe> [options]",
	Flags: []cli.Flag{
		internal.OnlyErrorFlag,
		internal.ChaosFlag,
	},
	Before:        internal.SubCommandBefore,
	ShellComplete: autocomplete.RecipeNameComplete,
	HideHelp:      true,
	Action: func(ctx context.Context, cmd *cli.Command) error {
		recipe := internal.ValidateRecipe(cmd)

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

		headers := []string{
			"ref",
			"rule",
			"severity",
			"satisfied",
			"skipped",
			"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 internal.OnlyErrors && rule.Level != "error" {
					log.Debugf("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 == "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 {
			fmt.Println(table)

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

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

		return nil
	},
}
