package transport

import (
	"encoding/json"
	"errors"
	"mime"
	"strconv"
	"strings"
)

const (
	latestMCPProtocolVersion  = "2025-11-25"
	defaultMCPProtocolVersion = "2025-03-26"
	mcpJSONMediaType          = "application/json"
	mcpSSEMediaType           = "text/event-stream"
)

func negotiateMCPProtocolVersion(raw json.RawMessage) (string, error) {
	var params struct {
		ProtocolVersion string `json:"protocolVersion"`
	}
	if len(raw) == 0 || json.Unmarshal(raw, &params) != nil || strings.TrimSpace(params.ProtocolVersion) == "" {
		return "", errors.New("initialize requires params.protocolVersion")
	}
	if isSupportedMCPProtocolVersion(params.ProtocolVersion) {
		return params.ProtocolVersion, nil
	}
	// MCP version negotiation returns a supported server version rather than
	// rejecting a syntactically valid client version. The client can disconnect
	// if it does not support this server's latest version.
	return latestMCPProtocolVersion, nil
}

func isSupportedMCPProtocolVersion(version string) bool {
	switch version {
	case defaultMCPProtocolVersion, "2025-06-18", latestMCPProtocolVersion:
		return true
	default:
		return false
	}
}

func isJSONUTF8(contentType string) bool {
	mediaType, params, err := mime.ParseMediaType(contentType)
	if err != nil || !strings.EqualFold(mediaType, mcpJSONMediaType) {
		return false
	}
	charset := strings.TrimSpace(params["charset"])
	return charset == "" || strings.EqualFold(charset, "utf-8")
}

func acceptsMediaType(header, target string) bool {
	bestSpecificity := -1
	bestQuality := 0.0
	for _, rawRange := range strings.Split(header, ",") {
		mediaRange, params, err := mime.ParseMediaType(strings.TrimSpace(rawRange))
		if err != nil {
			continue
		}
		specificity := mediaRangeSpecificity(mediaRange, target)
		if specificity < 0 {
			continue
		}
		quality := acceptQuality(params)
		if specificity > bestSpecificity || (specificity == bestSpecificity && quality > bestQuality) {
			bestSpecificity = specificity
			bestQuality = quality
		}
	}
	return bestQuality > 0
}

func acceptQuality(params map[string]string) float64 {
	raw, ok := params["q"]
	if !ok {
		return 1
	}
	quality, err := strconv.ParseFloat(raw, 64)
	if err != nil || quality < 0 || quality > 1 {
		return 0
	}
	return quality
}

func mediaRangeSpecificity(mediaRange, target string) int {
	if strings.EqualFold(mediaRange, target) {
		return 2
	}
	if mediaRange == "*/*" {
		return 0
	}
	parts := strings.SplitN(mediaRange, "/", 2)
	targetParts := strings.SplitN(target, "/", 2)
	if len(parts) == 2 && len(targetParts) == 2 && strings.EqualFold(parts[0], targetParts[0]) && parts[1] == "*" {
		return 1
	}
	return -1
}
