package common

import (
	"fmt"
	"os"
	"strconv"

	"github.com/spf13/cobra"

	"github.com/gitlink-org/gitlink-cli/cmd/cmdutil"
)

// MountShortcut converts a Shortcut into a cobra.Command and adds it as a subcommand.
func MountShortcut(parent *cobra.Command, s *Shortcut) {
	cmd := &cobra.Command{
		Use:   "+" + s.Name,
		Short: s.Description,
		RunE: func(cmd *cobra.Command, args []string) error {
			// Collect flag values
			flagValues := make(map[string]string)
			for _, f := range s.Flags {
				if f.Bool {
					val, _ := cmd.Flags().GetBool(f.Name)
					flagValues[f.Name] = strconv.FormatBool(val)
					continue
				}
				val, _ := cmd.Flags().GetString(f.Name)
				if val != "" {
					flagValues[f.Name] = val
				}
			}

			commandName := parent.Use + " +" + s.Name
			ctx, err := NewRuntimeContext(flagValues, commandName)
			if err != nil {
				return err
			}

			// Dry-run interception
			if s.DryRun {
				if dryRunVal, _ := cmd.Flags().GetBool("dry-run"); dryRunVal {
					flagValues["dry-run"] = "true"
					if s.DryRunHint != nil {
						hint, err := s.DryRunHint(ctx)
						if err != nil {
							return err
						}
						fmt.Fprintf(os.Stderr, "[dry-run] %s\n", hint)
					}
					proceed, err := ConfirmAction(ctx)
					if err != nil {
						return err
					}
					if !proceed {
						return nil
					}
				}
			}

			err = s.Run(ctx)
			if err != nil {
				// 当错误为已识别的 API/CLI 错误时，按 envelope 格式输出到 stdout，
				// 让 `--format json` 输出可被 jq 解析的标准结构。
				// 已识别后返回 ErrSilent：保留非零退出码，但 cmd.Execute 不会再 stderr 重复输出。
				if TryPrintError(err, ctx.Format) {
					return cmdutil.ErrSilent
				}
			}
			return err
		},
	}

	for _, f := range s.Flags {
		usage := f.Usage
		if f.Required {
			usage = usage + " [required]"
		}
		if f.Bool {
			defaultValue, _ := strconv.ParseBool(f.Default)
			if f.Short != "" {
				cmd.Flags().BoolP(f.Name, f.Short, defaultValue, usage)
			} else {
				cmd.Flags().Bool(f.Name, defaultValue, usage)
			}
		} else if f.Short != "" {
			cmd.Flags().StringP(f.Name, f.Short, f.Default, usage)
		} else {
			cmd.Flags().String(f.Name, f.Default, usage)
		}
	}

	// Auto-register --dry-run flag for shortcuts that support it
	if s.DryRun {
		cmd.Flags().Bool("dry-run", false, "Preview the operation without executing")
	}

	parent.AddCommand(cmd)
}

// MountShortcuts mounts multiple shortcuts under a parent command.
func MountShortcuts(parent *cobra.Command, shortcuts []*Shortcut) {
	for _, s := range shortcuts {
		MountShortcut(parent, s)
	}
}
