package schedule

import (
	"fmt"
	"sort"
	"strings"
)

// validateToolArgsStrict 校验工具参数是否全部命中 schema 白名单。
//
// 职责边界：
// 1. 只做“字段名是否允许”的校验，不校验字段值合法性；
// 2. 发现未知字段时直接报错，避免静默忽略导致范围漂移；
// 3. 该函数不做别名兼容，调用方应自行传入 schema 中允许的字段。
func validateToolArgsStrict(args map[string]any, allowedKeys []string) error {
	if len(args) == 0 {
		return nil
	}
	allowed := make(map[string]struct{}, len(allowedKeys))
	for _, key := range allowedKeys {
		allowed[strings.TrimSpace(key)] = struct{}{}
	}

	unknown := make([]string, 0, len(args))
	for key := range args {
		trimmed := strings.TrimSpace(key)
		if trimmed == "" {
			continue
		}
		if _, ok := allowed[trimmed]; ok {
			continue
		}
		unknown = append(unknown, trimmed)
	}
	if len(unknown) == 0 {
		return nil
	}

	sort.Strings(unknown)
	hint := "请仅使用当前工具 schema 中声明的参数字段。"
	if containsAnyUnknownArg(unknown, "day_from", "day_to") {
		hint = "请仅使用当前工具 schema 中声明的参数字段；day_from/day_to 不受支持，请改用 day_start/day_end。"
	}
	return fmt.Errorf("参数非法：%s。%s", strings.Join(unknown, "、"), hint)
}

func containsAnyUnknownArg(keys []string, targets ...string) bool {
	if len(keys) == 0 || len(targets) == 0 {
		return false
	}
	targetSet := make(map[string]struct{}, len(targets))
	for _, target := range targets {
		targetSet[strings.TrimSpace(target)] = struct{}{}
	}
	for _, key := range keys {
		if _, ok := targetSet[strings.TrimSpace(key)]; ok {
			return true
		}
	}
	return false
}
