package client

import (
	"encoding/json"
	"errors"

	"github.com/google/uuid"
)

type ToolHandlerInfo struct {
	UserId    uuid.UUID
	ImageId   uuid.UUID
	ImageName string

	// Pointer because we don't want to copy this around too much.
	Image *[]byte
}

type ToolHandler struct {
	Fn func(info ToolHandlerInfo, args string, call ToolCall) (string, error)
}

type ToolsHandlers struct {
	handlers map[string]ToolHandler
}

var NoToolCallError = errors.New("An assistant tool call with no tool calls was provided.")

const NonExistantTool = "This tool does not exist"

func (handler ToolsHandlers) Handle(info ToolHandlerInfo, toolCallMessage ToolCall) ChatUserToolResponse {
	fnName := toolCallMessage.Function.Name
	arguments := toolCallMessage.Function.Arguments

	responseMessage := ChatUserToolResponse{
		Role:       "tool",
		Name:       fnName,
		ToolCallId: toolCallMessage.Id,
	}

	fnHandler, exists := handler.handlers[fnName]
	if !exists {
		responseMessage.Content = NonExistantTool
		return responseMessage
	}

	res, err := fnHandler.Fn(info, arguments, toolCallMessage)

	if err != nil {
		responseMessage.Content = err.Error()
	} else {
		responseMessage.Content = res
	}

	return responseMessage
}

func (handler *ToolsHandlers) AddTool(name string, fn func(info ToolHandlerInfo, args string, call ToolCall) (any, error)) {
	handler.handlers[name] = ToolHandler{
		Fn: func(info ToolHandlerInfo, args string, call ToolCall) (string, error) {
			res, err := fn(info, args, call)
			if err != nil {
				return "", err
			}

			marshalledRes, err := json.Marshal(res)
			if err != nil {
				return "", err
			}

			return string(marshalledRes), nil
		},
	}
}
