package module

import (
	"fmt"
	"strings"
	"time"

	"ops-assistant/internal/core/policy"
	"ops-assistant/internal/core/runbook"
)

type CommandTemplate struct {
	RunbookName string
	Gate        Gate
	InputsFn    func(text string, parts []string) (map[string]string, error)
	MetaFn      func(userID int64, confirmToken string, inputs map[string]string) runbook.RunMeta
	DryRunMsg   string
	SuccessMsg  func(jobID uint) string
}

type CommandSpec struct {
	Prefixes  []string
	Template  CommandTemplate
	ErrPrefix string
	ErrHint   string
}

func ExecTemplate(runner *Runner, userID int64, raw string, tpl CommandTemplate) (uint, string, error) {
	dryRun, confirmToken := policy.ParseCommonFlags(raw)
	parts := strings.Fields(strings.TrimSpace(raw))
	inputs := map[string]string{}
	if tpl.InputsFn != nil {
		out, err := tpl.InputsFn(raw, parts)
		if err != nil {
			return 0, "", err
		}
		inputs = out
	}
	meta := runbook.NewMeta()
	if tpl.MetaFn != nil {
		meta = tpl.MetaFn(userID, confirmToken, inputs)
	}
	if meta.RequestID == "" {
		meta.RequestID = fmt.Sprintf("ops-u%d-%d", userID, time.Now().Unix())
	}
	req := Request{
		RunbookName:  tpl.RunbookName,
		Inputs:       inputs,
		Meta:         meta,
		Gate:         tpl.Gate,
		DryRun:       dryRun,
		ConfirmToken: confirmToken,
	}
	jobID, out, err := runner.Run(raw, userID, req)
	return jobID, out, err
}

func FormatDryRunMessage(tpl CommandTemplate) string {
	if tpl.DryRunMsg != "" {
		return tpl.DryRunMsg
	}
	return fmt.Sprintf("🧪 dry-run: 将执行 %s（未实际执行）", tpl.RunbookName)
}

func FormatSuccessMessage(tpl CommandTemplate, jobID uint) string {
	if tpl.SuccessMsg != nil {
		return tpl.SuccessMsg(jobID)
	}
	return fmt.Sprintf("✅ %s 已执行，job=%d", tpl.RunbookName, jobID)
}

func MatchAnyPrefix(text string, prefixes []string) bool {
	text = strings.TrimSpace(text)
	for _, p := range prefixes {
		if strings.HasPrefix(text, p) {
			return true
		}
	}
	return false
}

func MatchCommand(text string, specs []CommandSpec) (CommandSpec, bool) {
	for _, sp := range specs {
		if MatchAnyPrefix(text, sp.Prefixes) {
			return sp, true
		}
	}
	return CommandSpec{}, false
}

func FormatExecError(sp CommandSpec, err error) string {
	msg := sp.ErrPrefix + err.Error()
	if sp.ErrHint != "" {
		msg += "（示例：" + sp.ErrHint + "）"
	}
	return msg
}
