package services

import (
	"context"
	"slices"
	"strings"

	"agent-desk/internal/ai/mcps"
	"agent-desk/internal/pkg/config"
	"agent-desk/internal/pkg/enums"
	"agent-desk/internal/pkg/errorsx"
	"agent-desk/internal/pkg/i18nx"
	"agent-desk/internal/pkg/toolx"
)

var ToolCatalogService = newToolCatalogService()

func newToolCatalogService() *toolCatalogService {
	return &toolCatalogService{}
}

type toolCatalogService struct{}

type MCPToolCatalogItem struct {
	ToolCode     string
	ServerCode   string
	ToolName     string
	SourceType   enums.ToolSourceType
	AutoInjected bool
	Title        string
	Description  string
	InputSchema  any
	OutputSchema any
}

func (s *toolCatalogService) ListMCPTools(ctx context.Context) ([]MCPToolCatalogItem, error) {
	return s.ListMCPToolsWithLocale(ctx, i18nx.DefaultLocale)
}

func (s *toolCatalogService) ListMCPToolsWithLocale(ctx context.Context, locale string) ([]MCPToolCatalogItem, error) {
	cfg := config.Current()
	ret := make([]MCPToolCatalogItem, 0, 3)
	for _, spec := range toolx.ListAgentDirectToolSpecs() {
		if spec.Code == toolx.BuiltinToolSearch.Code && !cfg.MCP.Enabled {
			continue
		}
		ret = append(ret, MCPToolCatalogItem{
			ToolCode:     spec.Code,
			ServerCode:   spec.ServerCode,
			ToolName:     spec.Name,
			SourceType:   spec.SourceType,
			AutoInjected: spec.AutoInjected,
			Title:        toolx.GetRegisteredToolTitleLocale(spec.Code, locale),
			Description:  toolx.GetRegisteredToolDescriptionLocale(spec.Code, locale),
		})
	}
	if !cfg.MCP.Enabled {
		return ret, nil
	}
	serverCodes := make([]string, 0, len(cfg.MCP.Servers))
	for serverCode, server := range cfg.MCP.Servers {
		if !server.Enabled {
			continue
		}
		serverCodes = append(serverCodes, serverCode)
	}
	slices.Sort(serverCodes)
	for _, serverCode := range serverCodes {
		tools, err := mcps.Runtime.ListTools(ctx, serverCode)
		if err != nil {
			return nil, err
		}
		for _, item := range tools {
			ret = append(ret, MCPToolCatalogItem{
				ToolCode:     toolx.BuildMCPToolCode(serverCode, item.Name),
				ServerCode:   serverCode,
				ToolName:     strings.TrimSpace(item.Name),
				SourceType:   enums.ToolSourceTypeMCP,
				AutoInjected: false,
				Title:        strings.TrimSpace(item.Title),
				Description:  strings.TrimSpace(item.Description),
				InputSchema:  item.InputSchema,
				OutputSchema: item.OutputSchema,
			})
		}
	}
	return ret, nil
}

func (s *toolCatalogService) ValidateMCPToolCode(toolCode string) error {
	return s.ValidateToolCode(toolCode)
}

func (s *toolCatalogService) ValidateToolCode(toolCode string) error {
	cfg := config.Current()
	toolCode = strings.TrimSpace(toolCode)
	if toolCode == "" {
		return errorsx.InvalidParamI18n("error.e0074")
	}
	if toolx.IsAgentDirectToolCode(toolCode) {
		return nil
	}
	serverCode, toolName := toolx.SplitMCPToolCode(toolCode)
	if serverCode == "" || toolName == "" {
		return errorsx.InvalidParamI18n("error.e0075")
	}
	if !cfg.MCP.Enabled {
		return errorsx.InvalidParamI18n("error.e0035")
	}
	server, ok := cfg.MCP.Servers[serverCode]
	if !ok || !server.Enabled {
		return errorsx.InvalidParamI18n("error.e0073")
	}
	return nil
}
