package tool

import (
	"slices"
	"strings"

	"gitea.com/gitea/gitea-mcp/pkg/flag"
	"gitea.com/gitea/gitea-mcp/pkg/log"

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

type Tool struct {
	write []server.ServerTool
	read  []server.ServerTool
}

func New() *Tool {
	return &Tool{
		write: make([]server.ServerTool, 0, 100),
		read:  make([]server.ServerTool, 0, 100),
	}
}

func (t *Tool) RegisterWrite(s server.ServerTool) {
	t.write = append(t.write, s)
}

func (t *Tool) RegisterRead(s server.ServerTool) {
	t.read = append(t.read, s)
}

func (t *Tool) Tools() []server.ServerTool {
	all := make([]server.ServerTool, 0, len(t.write)+len(t.read))
	if !flag.ReadOnly {
		all = append(all, t.write...)
	}
	all = append(all, t.read...)
	if len(flag.AllowedTools) == 0 {
		return all
	}
	filtered := make([]server.ServerTool, 0, len(all))
	for _, st := range all {
		if _, ok := flag.AllowedTools[st.Tool.Name]; ok {
			filtered = append(filtered, st)
		}
	}
	return filtered
}

// WarnUnmatchedAllowedTools logs any names in flag.AllowedTools that don't
// match a tool registered on any of the given domains. No-op if the allowlist
// is empty.
func WarnUnmatchedAllowedTools(domains ...*Tool) {
	if len(flag.AllowedTools) == 0 {
		return
	}
	known := map[string]struct{}{}
	for _, d := range domains {
		for _, st := range d.read {
			known[st.Tool.Name] = struct{}{}
		}
		for _, st := range d.write {
			known[st.Tool.Name] = struct{}{}
		}
	}
	var unmatched []string
	for name := range flag.AllowedTools {
		if _, ok := known[name]; !ok {
			unmatched = append(unmatched, name)
		}
	}
	if len(unmatched) == 0 {
		return
	}
	slices.Sort(unmatched)
	log.Warnf("Unknown tools in --tools allowlist (ignored): %s", strings.Join(unmatched, ", "))
}
