package recorddefaultsv1

import (
	"context"
	"errors"
	"strings"
	"testing"
	"time"
)

func TestCreateDefaultPreviewContractAcceptsSiblingMaxAndCurrentPrincipal(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	parentField := "CampaignId"
	parentRecord := "701-test"
	revision := uint64(41)
	request := Request{
		ObjectID: "CampaignMemberStatus", ParentFieldID: &parentField,
		ParentRecordID: &parentRecord, MinCatalogRevision: &revision,
	}
	if err := ValidateRequest(ctx, request); err != nil {
		t.Fatalf("ValidateRequest() = %v", err)
	}
	next := int64(901)
	ownerID := "005-test"
	ownerName := "Test User"
	response := Response{
		Fields: []Field{
			{
				Name: "OwnerId", Kind: ValueReference, Reference: &ownerID,
				DisplayValue: &ownerName, Provenance: ProvenanceCurrentPrincipal,
			},
			{
				Name: "SortOrder", Kind: ValueInteger, Integer: &next,
				Provenance: ProvenanceSiblingMaxPlusOne,
			},
		},
		Receipts: Receipts{
			ProtocolVersion: "1.0", CapabilityVersion: CapabilityName,
			CatalogRevision: 41, SecurityEpoch: 7,
		},
	}
	if err := ValidateResponse(request, response); err != nil {
		t.Fatalf("ValidateResponse() = %v", err)
	}
}

func TestCreateDefaultPreviewRequestRequiresPairedParentContext(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	parentField := "CampaignId"
	err := ValidateRequest(ctx, Request{
		ObjectID: "CampaignMemberStatus", ParentFieldID: &parentField,
	})
	var failure *Failure
	if !errors.As(err, &failure) || failure.Category != FailureInvalidRequest ||
		failure.InvalidComponent != InvalidComponentRecordID {
		t.Fatalf("ValidateRequest(unpaired parent context) = %#v", err)
	}
}

func TestCreateDefaultPreviewRequestRejectsNilContext(t *testing.T) {
	err := ValidateRequest(nil, Request{ObjectID: "CampaignMemberStatus"})
	var failure *Failure
	if !errors.As(err, &failure) || failure.Category != FailureInvalidRequest ||
		failure.InvalidComponent != InvalidComponentDeadline {
		t.Fatalf("ValidateRequest(nil context) = %#v", err)
	}
}

func TestCreateDefaultPreviewRequestRejectsOversizedParentBeforeContentInspection(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	parentField := "CampaignId"
	parentRecord := strings.Repeat(" ", MaxRecordIdentifierBytes+1)
	err := ValidateRequest(ctx, Request{
		ObjectID: "CampaignMemberStatus", ParentFieldID: &parentField,
		ParentRecordID: &parentRecord,
	})
	var failure *Failure
	if !errors.As(err, &failure) || failure.Category != FailureResourceExhausted ||
		failure.LimitKind != LimitRecordID {
		t.Fatalf("ValidateRequest(oversized parent) = %#v", err)
	}
}

func TestCreateDefaultPreviewRejectsExplicitZeroCatalogMinimum(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	minimum := uint64(0)
	request := Request{ObjectID: "CampaignMemberStatus", MinCatalogRevision: &minimum}
	var failure *Failure
	if err := ValidateRequest(ctx, request); !errors.As(err, &failure) ||
		failure.Category != FailureInvalidRequest {
		t.Fatalf("ValidateRequest(zero Catalog minimum) = %#v", err)
	}
	response := Response{Receipts: Receipts{
		ProtocolVersion: "1.0", CapabilityVersion: CapabilityName,
	}}
	failure = nil
	if err := ValidateResponse(request, response); !errors.As(err, &failure) ||
		failure.Category != FailureInternal {
		t.Fatalf("ValidateResponse(zero Catalog minimum) = %#v", err)
	}
}

func TestCreateDefaultPreviewResponseRejectsForgedProvenanceShape(t *testing.T) {
	ownerID := "005-test"
	request := Request{ObjectID: "CampaignMemberStatus"}
	response := Response{
		Fields: []Field{{
			Name: "SortOrder", Kind: ValueReference, Reference: &ownerID,
			Provenance: ProvenanceSiblingMaxPlusOne,
		}},
		Receipts: Receipts{ProtocolVersion: "1.0", CapabilityVersion: CapabilityName},
	}
	var failure *Failure
	if err := ValidateResponse(request, response); !errors.As(err, &failure) ||
		failure.Category != FailureInternal {
		t.Fatalf("ValidateResponse(forged provenance) = %#v", err)
	}
}

func TestCreateDefaultPreviewResponseRejectsStaleCatalogReceipt(t *testing.T) {
	minimum := uint64(42)
	request := Request{ObjectID: "CampaignMemberStatus", MinCatalogRevision: &minimum}
	response := Response{Receipts: Receipts{
		ProtocolVersion: "1.0", CapabilityVersion: CapabilityName,
		CatalogRevision: 41,
	}}
	var failure *Failure
	if err := ValidateResponse(request, response); !errors.As(err, &failure) ||
		failure.Category != FailureInternal {
		t.Fatalf("ValidateResponse(stale Catalog receipt) = %#v", err)
	}
}

func TestCreateDefaultPreviewResponseRejectsOversizedDisplayBeforeSerialization(t *testing.T) {
	ownerID := "005-test"
	ownerName := strings.Repeat("x", MaxSemanticResponseBytes+1)
	request := Request{ObjectID: "CampaignMemberStatus"}
	response := Response{
		Fields: []Field{{
			Name: "OwnerId", Kind: ValueReference, Reference: &ownerID,
			DisplayValue: &ownerName, Provenance: ProvenanceCurrentPrincipal,
		}},
		Receipts: Receipts{ProtocolVersion: "1.0", CapabilityVersion: CapabilityName},
	}
	var failure *Failure
	if err := ValidateResponse(request, response); !errors.As(err, &failure) ||
		failure.Category != FailureResourceExhausted ||
		failure.LimitKind != LimitSemanticResponse {
		t.Fatalf("ValidateResponse(oversized DisplayValue) = %#v", err)
	}
}
