package main

import (
	"cmp"
	_ "embed"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/kami/maven/internal/ipc"
	"github.com/kami/maven/internal/tool"
	"github.com/kami/maven/internal/webauthn"
)

//go:embed tools.html
var toolsHTML string

// toolsTmpl — the enable surface. Server-rendered, no JS: a plain HTML form
// POSTs back to /tools to enable a proposal. html/template escapes tool names +
// utterances (they came from voice STT — untrusted text).
var toolsTmpl = parsePage("tools", toolsHTML, template.FuncMap{
	"join":       strings.Join,
	"capability": func(t ipc.Tool) string { return tool.CapabilityOf(t).String() },
	"risk":       func(t ipc.Tool) string { return string(tool.RiskOf(t)) },
})

// handleTools serves the enable surface (GET) and applies an enable (POST).
// POST fields: name, cmd (space-separated argv), destructive (checkbox). cmd is
// whitespace-split — argv with embedded spaces isn't supported (ponytail: no
// shell-word parsing; the box owner controls this input, quote a wrapper script
// if an arg needs spaces).
func handleTools(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI, session *webauthn.PasskeySession, requireStepUp bool) {
	if !requireCore(w, core, "tools") {
		return
	}
	ctx := r.Context()
	var msg string
	if r.Method == http.MethodPost {
		if !stepUpGate(w, session, requireStepUp) {
			return
		}
		action := r.FormValue("action")
		name := strings.TrimSpace(r.FormValue("name"))
		switch action {
		case "enable":
			scope := r.FormValue("scope")
			cmd := strings.Fields(r.FormValue("cmd"))
			destructive := r.FormValue("destructive") != ""
			if name == "" || len(cmd) == 0 {
				http.Error(w, "name and cmd required", http.StatusBadRequest)
				return
			}
			if err := core.EnableTool(ctx, name, cmd, destructive, scope, time.Now()); err != nil {
				log.Printf("tools: enable %q: %v", name, err)
				http.Error(w, "enable failed: "+err.Error(), http.StatusBadGateway)
				return
			}
			msg = "enabled " + name
		case "disable":
			if name == "" {
				http.Error(w, "name required", http.StatusBadRequest)
				return
			}
			if err := core.DisableTool(ctx, name); err != nil {
				log.Printf("tools: disable %q: %v", name, err)
				http.Error(w, "disable failed: "+err.Error(), http.StatusBadGateway)
				return
			}
			msg = "disabled " + name
		case "dismiss":
			if name == "" {
				http.Error(w, "name required", http.StatusBadRequest)
				return
			}
			if err := core.DeleteTool(ctx, name); err != nil {
				log.Printf("tools: dismiss %q: %v", name, err)
				http.Error(w, "dismiss failed: "+err.Error(), http.StatusBadGateway)
				return
			}
			msg = "dismissed " + name
		default:
			http.Error(w, "unknown action", http.StatusBadRequest)
			return
		}
	}
	proposed, err1 := core.ListTools(ctx, "proposed")
	enabled, err2 := core.ListTools(ctx, "enabled")
	if err := cmp.Or(err1, err2); err != nil {
		log.Printf("tools: %v", err)
		http.Error(w, "core read failed", http.StatusBadGateway)
		return
	}
	// MCP is off by default and an older core may not know the method at all,
	// so a failure here renders an empty section rather than breaking the page.
	servers, err := core.MCPServers(ctx)
	if err != nil {
		log.Printf("tools: mcp servers: %v", err)
		servers = nil
	}
	// Enabled rows are shown grouped by capability domain (Vikunja #452). A
	// flat list stops answering "what can she do to the house" somewhere
	// around fifteen rows, and that is the question this page exists for.
	renderPage(w, toolsTmpl, struct {
		Msg      string
		Proposed []ipc.Tool
		Enabled  []ipc.Tool
		Groups   []tool.CapabilityGroup
		MCP      []ipc.MCPServerStatus
	}{msg, proposed, enabled, tool.GroupByDomain(enabled), servers})
}
