// Copyright 2026 printing-press-golden. Licensed under Apache-2.0. See LICENSE.
// Generated by CLI Printing Press (https://github.com/mvanhorn/cli-printing-press). DO NOT EDIT.

package cobratree

import (
	"context"
	"fmt"
	"os/exec"
	"sort"
	"strconv"
	"strings"

	mcplib "github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
)

func shellOutToCLI(cliPath func() (string, error), commandPath []string) server.ToolHandlerFunc {
	lookupPath, lookupErr := cliPath()
	prefixArgs := append([]string{}, commandPath...)
	return func(ctx context.Context, req mcplib.CallToolRequest) (*mcplib.CallToolResult, error) {
		if lookupErr != nil {
			return mcplib.NewToolResultError(fmt.Sprintf("companion CLI binary not found: %v\nTried sibling lookup, PRINTING_PRESS_GOLDEN_CLI_PATH env var, and PATH.", lookupErr)), nil
		}
		args := req.GetArguments()
		finalArgs := append([]string{}, prefixArgs...)
		finalArgs = append(finalArgs, cliArgsFromMCP(args)...)
		if raw, _ := args["args"].(string); strings.TrimSpace(raw) != "" {
			tokens := splitShellArgs(raw)
			for _, t := range tokens {
				if strings.HasPrefix(t, "-") {
					return mcplib.NewToolResultError(fmt.Sprintf("flag-like argument %q not allowed in positional args field; use structured tool parameters instead", t)), nil
				}
			}
			finalArgs = append(finalArgs, tokens...)
		}
		cmd := exec.CommandContext(ctx, lookupPath, finalArgs...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			return mcplib.NewToolResultError(string(out)), nil
		}
		return mcplib.NewToolResultText(string(out)), nil
	}
}

// blockedRootFlags are root-level CLI flags that an MCP client must not be
// able to override via structured tool parameters. Allowing them lets a
// caller swap auth credentials, redirect the API base URL, load a malicious
// config file, or change the delivery target — all of which sit outside the
// per-command surface the agent is supposed to be calling.
var blockedRootFlags = map[string]bool{
	"args":     true,
	"base-url": true,
	"config":   true,
	"deliver":  true,
	"profile":  true,
	"token":    true,
}

func cliArgsFromMCP(args map[string]any) []string {
	keys := make([]string, 0, len(args))
	for k := range args {
		if !blockedRootFlags[k] {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)

	var out []string
	for _, k := range keys {
		v := args[k]
		switch tv := v.(type) {
		case bool:
			if tv {
				out = append(out, "--"+k)
			}
		case float64:
			out = append(out, "--"+k, strconv.FormatFloat(tv, 'f', -1, 64))
		case string:
			if tv != "" {
				out = append(out, "--"+k, tv)
			}
		case []any:
			if len(tv) > 0 {
				parts := make([]string, 0, len(tv))
				for _, item := range tv {
					parts = append(parts, fmt.Sprintf("%v", item))
				}
				out = append(out, "--"+k, strings.Join(parts, ","))
			}
		default:
			if v != nil {
				out = append(out, "--"+k, fmt.Sprintf("%v", v))
			}
		}
	}
	return out
}

// splitShellArgs whitespace-splits with double-quoted-token preservation.
func splitShellArgs(s string) []string {
	var tokens []string
	var cur []rune
	inQuote := false
	for _, r := range s {
		switch {
		case r == '"':
			inQuote = !inQuote
		case (r == ' ' || r == '\t') && !inQuote:
			if len(cur) > 0 {
				tokens = append(tokens, string(cur))
				cur = cur[:0]
			}
		default:
			cur = append(cur, r)
		}
	}
	if len(cur) > 0 {
		tokens = append(tokens, string(cur))
	}
	return tokens
}
