package knowledgeqa

import (
	"regexp"
	"strings"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/knowledgeqa/protocol"
)

var (
	knowledgeQASessionIDPattern = regexp.MustCompile(`^kqs_[a-z0-9_]{8,59}$`)
	idempotencyKeyPattern       = regexp.MustCompile(`^[A-Za-z0-9._:/-]{8,128}$`)
)

func requireIdempotencyKey(ctx *gin.Context) (string, error) {
	key := strings.TrimSpace(ctx.GetHeader("Idempotency-Key"))
	if !idempotencyKeyPattern.MatchString(key) {
		return "", invalidRequest("A valid Idempotency-Key header is required")
	}
	return key, nil
}

func validateCreateSessionRequest(request dto.KnowledgeQACreateSessionRequest) error {
	if strings.TrimSpace(request.SessionID) == "" ||
		strings.TrimSpace(request.RootMessageID) == "" ||
		strings.TrimSpace(request.ThreadChannelID) == "" ||
		strings.TrimSpace(request.UserMessageID) == "" ||
		strings.TrimSpace(request.Question) == "" ||
		strings.TrimSpace(request.Model) == "" ||
		strings.TrimSpace(request.ReasonLevel) == "" {
		return invalidRequest("sessionId, rootMessageId, threadChannelId, userMessageId, question, model, and reasonLevel are required")
	}
	if strings.TrimSpace(request.UserMessageID) != strings.TrimSpace(request.RootMessageID) {
		return invalidRequest("The initial user message must be the reply thread root")
	}
	if sessionID := strings.TrimSpace(request.SessionID); !knowledgeQASessionIDPattern.MatchString(sessionID) {
		return invalidRequest("sessionId must be a Knowledge Q&A opaque identifier")
	}
	if _, _, err := protocol.NormalizeSelection(request.Model, request.ReasonLevel); err != nil {
		return invalidRequest(err.Error())
	}
	return nil
}

func optionalScope(values []string) []string {
	if values == nil {
		return nil
	}
	result := make([]string, 0, len(values))
	seen := make(map[string]struct{}, len(values))
	for _, value := range values {
		value = strings.TrimSpace(value)
		if value == "" {
			continue
		}
		if _, ok := seen[value]; ok {
			continue
		}
		seen[value] = struct{}{}
		result = append(result, value)
	}
	return result
}

func routeParameter(ctx *gin.Context, name string) string {
	return strings.TrimSpace(ctx.Param(name))
}

func trimmed(value string) string {
	return strings.TrimSpace(value)
}
