package cli

import (
	"fmt"
	"os"

	"github.com/pkg/errors"
	"github.com/replicatedhq/troubleshoot/pkg/constants"
	"github.com/replicatedhq/troubleshoot/pkg/lint"
	"github.com/replicatedhq/troubleshoot/pkg/types"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func LintCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "lint [spec-files...]",
		Args:  cobra.MinimumNArgs(1),
		Short: "Lint v1beta2/v1beta3 preflight specs for syntax and structural errors",
		Long: `Lint v1beta2/v1beta3 preflight specs for syntax and structural errors.

This command validates v1beta2/v1beta3 preflight specs and checks for:
- YAML syntax errors
- Missing required fields (apiVersion, kind, metadata, spec)
- Invalid template syntax ({{ .Values.* }})
- Missing analyzers or collectors
- Common structural issues
- Missing docStrings (warning)

Examples:
  # Lint a single spec file
  preflight lint my-preflight.yaml

  # Lint multiple spec files
  preflight lint spec1.yaml spec2.yaml spec3.yaml

  # Lint with automatic fixes
  preflight lint --fix my-preflight.yaml

  # Lint and output as JSON for CI/CD integration
  preflight lint --format json my-preflight.yaml

Notes:
- v1beta2 does not support templating; template syntax in v1beta2 files will be flagged as errors.
- v1beta3 supports templating and is linted with template-awareness.

Exit codes:
  0 - No errors found
  2 - Validation errors found`,
		PreRun: func(cmd *cobra.Command, args []string) {
			viper.BindPFlags(cmd.Flags())
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			v := viper.GetViper()

			opts := lint.LintOptions{
				FilePaths:   args,
				Fix:         v.GetBool("fix"),
				Format:      v.GetString("format"),
				ValuesFiles: v.GetStringSlice("values"),
				SetValues:   v.GetStringSlice("set"),
			}

			return runLint(opts)
		},
	}

	cmd.Flags().Bool("fix", false, "Automatically fix issues where possible")
	cmd.Flags().String("format", "text", "Output format: text or json")
	cmd.Flags().StringSlice("values", []string{}, "Path to YAML files with template values (required for v1beta3 specs)")
	cmd.Flags().StringSlice("set", []string{}, "Set template values via command line (e.g., --set key=value)")

	return cmd
}

func runLint(opts lint.LintOptions) error {
	// Validate file paths exist
	for _, filePath := range opts.FilePaths {
		if _, err := os.Stat(filePath); err != nil {
			return errors.Wrapf(err, "file not found: %s", filePath)
		}
	}

	// Run linting
	results, err := lint.LintFiles(opts)
	if err != nil {
		return errors.Wrap(err, "failed to lint files")
	}

	// Format and print results
	output := lint.FormatResults(results, opts.Format)
	fmt.Print(output)

	// Return appropriate exit code
	if lint.HasErrors(results) {
		return types.NewExitCodeError(constants.EXIT_CODE_SPEC_ISSUES, nil)
	}

	return nil
}
