package reportv1

import (
	"context"
	"encoding/json"
	"strings"
	"unicode"
	"unicode/utf8"

	common "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	mutation "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordmutationv1"
)

func ValidateRequest(ctx context.Context, request Request) error {
	if err := validateContext(ctx); err != nil {
		return err
	}
	if request.Offset > MaxOffset {
		return &Failure{Category: common.FailureResourceExhausted, LimitKind: common.LimitQueryOffset, Maximum: MaxOffset}
	}
	if !validText(request.ReportID) || request.Limit == 0 || request.Limit > MaxRows ||
		!validCanonicalJSON(request.CanonicalFilters, MaxSemanticRequestBytes) {
		return invalid(common.InvalidComponentQueryPlan)
	}
	return validateSize(request, MaxSemanticRequestBytes, common.LimitSemanticRequest)
}

func ValidateResponse(response Response) error {
	if !common.ValidReceipts(response.Receipts, CapabilityName) ||
		!validCanonicalJSON(response.CanonicalResult, MaxSemanticResponseBytes) {
		return internal()
	}
	return validateSize(response, MaxSemanticResponseBytes, common.LimitSemanticResponse)
}

func validCanonicalJSON(value []byte, maximum int) bool {
	if len(value) == 0 || len(value) > maximum || !utf8.Valid(value) {
		return false
	}
	canonical, err := mutation.CanonicalSourceJSON(string(value))
	return err == nil && string(value) == canonical
}

func validText(value string) bool {
	if value == "" || len(value) > MaxIdentifierBytes || !utf8.ValidString(value) ||
		strings.TrimSpace(value) != value {
		return false
	}
	for _, r := range value {
		if unicode.IsControl(r) {
			return false
		}
	}
	return true
}

func validateContext(ctx context.Context) error {
	if ctx == nil {
		return invalid(common.InvalidComponentDeadline)
	}
	if err := ctx.Err(); err != nil {
		if err == context.DeadlineExceeded {
			return &Failure{Category: common.FailureDeadlineExceeded}
		}
		return &Failure{Category: common.FailureCanceled}
	}
	if _, ok := ctx.Deadline(); !ok {
		return invalid(common.InvalidComponentDeadline)
	}
	return nil
}

func validateSize(value any, maximum int, kind common.LimitKind) error {
	encoded, err := json.Marshal(value)
	if err != nil {
		return internal()
	}
	if len(encoded) > maximum {
		return &Failure{Category: common.FailureResourceExhausted, LimitKind: kind, Maximum: uint64(maximum)}
	}
	return nil
}

func invalid(component common.InvalidComponent) *Failure {
	return &Failure{Category: common.FailureInvalidRequest, InvalidComponent: component}
}
func internal() *Failure { return &Failure{Category: common.FailureInternal} }
