package cli

import (
	"fmt"
	"io"
	"log/slog"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"

	"github.com/tidbcloud/observability/vm-migration/internal/printer"
)

// Verbosity levels for -v flag (default is 2).
const (
	verbosityError = 0
	verbosityWarn  = 1
	verbosityInfo  = 2
	verbosityDebug = 3
)

// NewRootCmd returns the root cobra command.
//
// The -v flag sets slog verbosity: 0=error, 1=warn, 2=info (default), 3=debug.
// Logs write to stderr; operator progress output writes to stdout.
func NewRootCmd() *cobra.Command {
	var verbosity int
	root := &cobra.Command{
		Use:   "vm-migration",
		Short: "VMCluster vmstorage tenant migration tool",
		Long: `Migrate dedicated tenant history data across vmstorage topologies.

Local commands author the inputs — tenant discovery, plan init / compile.
Execution (manifest generation, vmctl migration, verification) runs in the
long-running serve HTTP service.`,
		SilenceUsage:  true,
		SilenceErrors: true,
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			return setupLogger(verbosity, cmd.ErrOrStderr())
		},
	}
	root.PersistentFlags().IntVarP(&verbosity, "v", "v", verbosityInfo,
		"Log verbosity: 0=error, 1=warn, 2=info, 3=debug")

	root.AddCommand(
		newPlanCmd(),
		newTenantsCmd(),
		newServeCmd(),
		newVersionCmd(),
	)
	return root
}

// setupLogger configures the default slog logger with the given verbosity.
//
// Logs write to stderr; stdout remains clean for structured output.
func setupLogger(verbosity int, diagnostic io.Writer) error {
	var lvl slog.Level
	switch verbosity {
	case verbosityError:
		lvl = slog.LevelError
	case verbosityWarn:
		lvl = slog.LevelWarn
	case verbosityInfo:
		lvl = slog.LevelInfo
	case verbosityDebug:
		lvl = slog.LevelDebug
	default:
		return fmt.Errorf("invalid -v %d (want 0..3 where 0=error 1=warn 2=info 3=debug)", verbosity)
	}
	handler := slog.NewTextHandler(diagnostic, &slog.HandlerOptions{Level: lvl})
	slog.SetDefault(slog.New(handler))
	return nil
}

func newVersionCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "version",
		Short: "Print vm-migration version",
		Args:  cobra.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			printer.Printf(cmd.OutOrStdout(), "%s", String())
			return nil
		},
	}
}

// defaultMigrationsDir returns dir, or $PWD/migrations when dir is empty.
func defaultMigrationsDir(dir string) (string, error) {
	if dir != "" {
		return dir, nil
	}
	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	return filepath.Join(cwd, "migrations"), nil
}
