package auditlogv1

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

func TestAuditLogRequestAndResponseAreBoundedAndOrdered(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	request := Request{ObjectID: "Account", RecordID: "001-record", Limit: 100}
	if err := ValidateRequest(ctx, request); err != nil {
		t.Fatalf("request = %v", err)
	}
	response := Response{
		Rows: []Row{
			{ID: "row-b", ObjectID: "Account", RecordID: "001-record", FieldID: "Name", ChangedByID: "005", ChangedAt: "2026-08-14T12:00:00Z"},
			{ID: "row-a", ObjectID: "Account", RecordID: "001-record", FieldID: "Name", ChangedByID: "005", ChangedAt: "2026-08-14T12:00:00Z"},
		},
		Receipts: Receipts{ProtocolVersion: "1.0", CapabilityVersion: CapabilityName},
	}
	if err := ValidateResponse(response); err != nil {
		t.Fatalf("response = %v", err)
	}
	if err := ValidateResponseForRequest(request, response); err != nil {
		t.Fatalf("response for request = %v", err)
	}
	reversed := response
	reversed.Rows = append([]Row(nil), response.Rows...)
	reversed.Rows[0], reversed.Rows[1] = reversed.Rows[1], reversed.Rows[0]
	if err := ValidateResponse(reversed); err == nil {
		t.Fatal("expected non-canonical equal-time ID order rejection")
	}
	mismatched := response
	mismatched.Rows = append([]Row(nil), response.Rows...)
	mismatched.Rows[0].RecordID = "other-record"
	if err := ValidateResponseForRequest(request, mismatched); err == nil {
		t.Fatal("expected record outside requested authority rejection")
	}
	limited := request
	limited.Limit = 1
	if err := ValidateResponseForRequest(limited, response); err == nil {
		t.Fatal("expected response above requested page limit rejection")
	}
	minimum := uint64(2)
	stale := request
	stale.MinCatalogRevision = &minimum
	response.Receipts.CatalogRevision = minimum - 1
	if err := ValidateResponseForRequest(stale, response); err == nil {
		t.Fatal("expected response below requested Catalog revision rejection")
	}
}

func TestAuditLogRequestRequiresDeadlineIdentityAndBounds(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	for _, request := range []Request{
		{ObjectID: "", RecordID: "001", Limit: 1},
		{ObjectID: "Account", RecordID: "", Limit: 1},
		{ObjectID: "Account", RecordID: "001", Limit: 0},
		{ObjectID: "Account", RecordID: "001", Limit: MaxRows + 1},
		{ObjectID: "Account", RecordID: "001", Limit: 1, Offset: MaxOffset + 1},
		{ObjectID: "Account", RecordID: "001", Limit: 1, MinCatalogRevision: new(uint64)},
	} {
		var failure *Failure
		if err := ValidateRequest(ctx, request); !errors.As(err, &failure) || failure.Category != FailureInvalidRequest {
			t.Fatalf("request %#v = %#v", request, err)
		}
	}
	var failure *Failure
	if err := ValidateRequest(context.Background(), Request{ObjectID: "Account", RecordID: "001", Limit: 1}); !errors.As(err, &failure) || failure.InvalidComponent != InvalidComponentDeadline {
		t.Fatalf("deadline failure = %#v", err)
	}
	if err := ValidateRequest(nil, Request{ObjectID: "Account", RecordID: "001", Limit: 1}); !errors.As(err, &failure) || failure.InvalidComponent != InvalidComponentDeadline {
		t.Fatalf("nil context failure = %#v", err)
	}
}
