package tools

import (
	"encoding/json"
	"fmt"
	"strings"

	"git.warky.dev/wdevs/amcs/internal/config"
	"git.warky.dev/wdevs/amcs/internal/mcperrors"
	"github.com/modelcontextprotocol/go-sdk/jsonrpc"
)

func normalizeLimit(limit int, cfg config.SearchConfig) int {
	if limit <= 0 {
		return cfg.DefaultLimit
	}
	if limit > cfg.MaxLimit {
		return cfg.MaxLimit
	}
	return limit
}

func normalizeThreshold(value float64, fallback float64) float64 {
	if value <= 0 {
		return fallback
	}
	if value > 1 {
		return 1
	}
	return value
}

const (
	codeSessionRequired = mcperrors.CodeSessionRequired
	codeProjectRequired = mcperrors.CodeProjectRequired
	codeProjectNotFound = mcperrors.CodeProjectNotFound
	codeInvalidID       = mcperrors.CodeInvalidID
	codeEntityNotFound  = mcperrors.CodeEntityNotFound
)

type mcpErrorData = mcperrors.Data

func newMCPError(code int64, message string, data mcpErrorData) error {
	rpcErr := &jsonrpc.Error{
		Code:    code,
		Message: message,
	}

	payload, err := json.Marshal(data)
	if err != nil {
		return fmt.Errorf("marshal mcp error data: %w", err)
	}
	rpcErr.Data = payload

	return rpcErr
}

func errInvalidInput(message string) error {
	return newMCPError(
		jsonrpc.CodeInvalidParams,
		"invalid input: "+message,
		mcpErrorData{
			Type: mcperrors.TypeInvalidInput,
		},
	)
}

func errRequiredField(field string) error {
	return newMCPError(
		jsonrpc.CodeInvalidParams,
		field+" is required",
		mcpErrorData{
			Type:   mcperrors.TypeInvalidInput,
			Field:  field,
			Detail: "required",
			Hint:   "provide " + field,
		},
	)
}

func errInvalidField(field string, message string, hint string) error {
	return newMCPError(
		jsonrpc.CodeInvalidParams,
		message,
		mcpErrorData{
			Type:   mcperrors.TypeInvalidInput,
			Field:  field,
			Detail: "invalid",
			Hint:   hint,
		},
	)
}

func errOneOfRequired(fields ...string) error {
	return newMCPError(
		jsonrpc.CodeInvalidParams,
		joinFields(fields)+" is required",
		mcpErrorData{
			Type:   mcperrors.TypeInvalidInput,
			Fields: fields,
			Detail: "one_of_required",
			Hint:   "provide one of: " + strings.Join(fields, ", "),
		},
	)
}

func errMutuallyExclusiveFields(fields ...string) error {
	return newMCPError(
		jsonrpc.CodeInvalidParams,
		"provide "+joinFields(fields)+", not both",
		mcpErrorData{
			Type:   mcperrors.TypeInvalidInput,
			Fields: fields,
			Detail: "mutually_exclusive",
			Hint:   "provide only one of: " + strings.Join(fields, ", "),
		},
	)
}

func errEntityNotFound(entity string, field string, value string) error {
	return newMCPError(
		codeEntityNotFound,
		entity+" not found",
		mcpErrorData{
			Type:   mcperrors.TypeEntityNotFound,
			Entity: entity,
			Field:  field,
			Value:  value,
			Detail: "not_found",
		},
	)
}

func joinFields(fields []string) string {
	switch len(fields) {
	case 0:
		return "field"
	case 1:
		return fields[0]
	case 2:
		return fields[0] + " or " + fields[1]
	default:
		return strings.Join(fields[:len(fields)-1], ", ") + ", or " + fields[len(fields)-1]
	}
}
