package analytics

import (
	"context"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/nexuscrm/kernel/pkg/ports"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/shared/pkg/queryspec"
)

func TestVirtualReportSourceCarriesNeutralReportPlan(t *testing.T) {
	source := &workItemTimelineSource{}
	permissions := &virtualReportPermissionChecker{}
	queries := &virtualReportQueryService{}
	service := NewReportService(queries, virtualReportMetadata{}, permissions, nil)
	if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}

	definition := &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"Id", "Status", "QueueName", "AgeDays"},
		Filters: []models.ReportFilter{{
			Column:   "Status",
			Operator: "equals",
			Value:    "open",
		}},
		Grouping: []string{"QueueName"},
		Aggregates: []models.ReportAggregate{{
			Field: "AgeDays",
			Type:  "AVG",
		}},
	}
	result, err := service.RunReportDefinitionPage(
		context.Background(),
		definition,
		&models.UserSession{ID: "user-1"},
		map[string]interface{}{"Status": "open"},
		25,
		10,
	)
	if err != nil {
		t.Fatalf("RunReportDefinitionPage: %v", err)
	}
	if source.request.Limit != 25 || source.request.Offset != 10 {
		t.Fatalf("pagination = (%d, %d), want (25, 10)", source.request.Limit, source.request.Offset)
	}
	if !reflect.DeepEqual(source.request.Definition.Filters, definition.Filters) {
		t.Fatalf("filters = %#v, want %#v", source.request.Definition.Filters, definition.Filters)
	}
	if !reflect.DeepEqual(source.request.Definition.Grouping, definition.Grouping) {
		t.Fatalf("grouping = %#v, want %#v", source.request.Definition.Grouping, definition.Grouping)
	}
	if len(source.request.Joins) != 1 || source.request.Joins[0].Name != "queue" {
		t.Fatalf("joins = %#v, want queue join", source.request.Joins)
	}
	var sawDerived bool
	for _, column := range source.request.Columns {
		if column.Name == "AgeDays" {
			sawDerived = column.Derived
		}
	}
	if !sawDerived {
		t.Fatalf("requested columns = %#v, want derived AgeDays", source.request.Columns)
	}
	if len(result.Rows) != 20 {
		t.Fatalf("row count = %d, want 20 filtered rows after offset", len(result.Rows))
	}
	for _, row := range result.Rows {
		if row["Status"] != "open" || row["QueueName"] == "" {
			t.Fatalf("row = %#v, want grouped open work item", row)
		}
	}
	if result.ReportMetadata.DisplayMode != "SUMMARY" {
		t.Fatalf("display mode = %q, want SUMMARY", result.ReportMetadata.DisplayMode)
	}
	if result.TotalCount != 30 {
		t.Fatalf("total count = %d, want 30 filtered rows", result.TotalCount)
	}
	if queries.calls != 2 {
		t.Fatalf("authoritative query calls = %d, want 2 batched object queries", queries.calls)
	}
}

func TestVirtualReportSourceFailsClosed(t *testing.T) {
	t.Run("undeclared filter", func(t *testing.T) {
		source := &workItemTimelineSource{}
		service := newVirtualReportService(&virtualReportPermissionChecker{})
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Filters:   []models.ReportFilter{{Column: "Secret", Operator: "equals", Value: "x"}},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("undeclared filter succeeded, want fail-closed error")
		}
		if source.calls != 0 {
			t.Fatalf("source calls = %d, want 0", source.calls)
		}
	})

	t.Run("field FLS denied", func(t *testing.T) {
		source := &workItemTimelineSource{}
		permissions := &virtualReportPermissionChecker{deniedField: "Status"}
		service := newVirtualReportService(permissions)
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Status"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("FLS-denied field succeeded, want fail-closed error")
		}
		if source.calls != 0 {
			t.Fatalf("source calls = %d, want 0", source.calls)
		}
	})

	t.Run("source field is not a declared FLS dependency", func(t *testing.T) {
		source := &workItemTimelineSource{recordFieldOverride: "Secret"}
		service := newVirtualReportService(&virtualReportPermissionChecker{})
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Status"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("hidden source field succeeded, want fail-closed error")
		}
	})

	t.Run("missing parent access evidence", func(t *testing.T) {
		source := &workItemTimelineSource{omitAccessEvidence: true}
		service := newVirtualReportService(&virtualReportPermissionChecker{})
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Status"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("row without parent access evidence succeeded, want fail-closed error")
		}
	})

	t.Run("parent record denied", func(t *testing.T) {
		source := &workItemTimelineSource{}
		queries := &virtualReportQueryService{omitObject: "WorkItem"}
		service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Id"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("RLS-denied parent record succeeded, want fail-closed error")
		}
	})

	t.Run("missing joined access evidence", func(t *testing.T) {
		source := &workItemTimelineSource{omitJoinAccessEvidence: true}
		service := newVirtualReportService(&virtualReportPermissionChecker{})
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"QueueName"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("row without joined access evidence succeeded, want fail-closed error")
		}
	})

	t.Run("row field dependency denied", func(t *testing.T) {
		source := &workItemTimelineSource{}
		permissions := &virtualReportPermissionChecker{deniedField: "Status"}
		service := newVirtualReportService(permissions)
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Id"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("row with denied dynamic dependency succeeded, want fail-closed error")
		}
	})

	t.Run("missing value-bound row field evidence", func(t *testing.T) {
		source := &workItemTimelineSource{omitRowFieldEvidence: true}
		service := newVirtualReportService(&virtualReportPermissionChecker{})
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Id"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("value without row field evidence succeeded, want fail-closed error")
		}
	})

	t.Run("row field evidence on non-parent object", func(t *testing.T) {
		source := &workItemTimelineSource{rowFieldObject: "Queue"}
		service := newVirtualReportService(&virtualReportPermissionChecker{})
		if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
			t.Fatalf("RegisterVirtualReportSource: %v", err)
		}
		_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Id"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		if err == nil {
			t.Fatal("non-parent row field evidence succeeded, want fail-closed error")
		}
	})
}

func TestVirtualReportSourcePropagatesCancellation(t *testing.T) {
	source := &workItemTimelineSource{waitForCancellation: true, entered: make(chan struct{})}
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	ctx, cancel := context.WithCancel(context.Background())
	errCh := make(chan error, 1)
	go func() {
		_, err := service.RunReportDefinitionPage(ctx, &models.ReportDefinition{
			SourceRef: "WorkItemTimeline",
			Columns:   []string{"Id"},
		}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
		errCh <- err
	}()
	<-source.entered
	cancel()
	err := <-errCh
	if !errors.Is(err, context.Canceled) {
		t.Fatalf("error = %v, want context.Canceled", err)
	}
}

func TestVirtualReportSourceProjectsMissingOptionalJoinAsNull(t *testing.T) {
	source := &workItemTimelineSource{omitJoinAccessEvidence: true, omitJoinValueEvidence: true}
	queries := &virtualReportQueryService{omitParentQueueID: true}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := workItemTimelineRegistration(source)
	registration.Joins[0].Optional = true
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	result, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
	if err != nil {
		t.Fatalf("RunReportDefinitionPage: %v", err)
	}
	if len(source.request.Joins) != 1 || !source.request.Joins[0].Optional {
		t.Fatalf("requested joins = %#v, want optional queue join", source.request.Joins)
	}
	if len(result.Rows) != 20 {
		t.Fatalf("row count = %d, want 20", len(result.Rows))
	}
	for _, row := range result.Rows {
		if row["QueueName"] != nil {
			t.Fatalf("QueueName = %#v, want nil for missing optional join", row["QueueName"])
		}
	}
	if queries.calls != 1 {
		t.Fatalf("authoritative query calls = %d, want parent query only", queries.calls)
	}
}

func TestVirtualReportSourceRejectsContradictedOptionalJoinAbsence(t *testing.T) {
	source := &workItemTimelineSource{omitJoinAccessEvidence: true, omitJoinValueEvidence: true}
	queries := &virtualReportQueryService{parentQueueIDOverride: "queue-present"}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := workItemTimelineRegistration(source)
	registration.Joins[0].Optional = true
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil || !strings.Contains(err.Error(), "relationship evidence is contradicted") {
		t.Fatalf("error = %v, want contradicted relationship evidence", err)
	}
}

func TestVirtualReportSourceRejectsMismatchedJoinRelationship(t *testing.T) {
	source := &workItemTimelineSource{}
	queries := &virtualReportQueryService{parentQueueIDOverride: "queue-other"}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := workItemTimelineRegistration(source)
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil || !strings.Contains(err.Error(), "relationship evidence is contradicted") {
		t.Fatalf("error = %v, want mismatched relationship evidence", err)
	}
}

func TestVirtualReportSourceRequiresOptionalJoinAbsenceFieldPermission(t *testing.T) {
	source := &workItemTimelineSource{omitJoinAccessEvidence: true, omitJoinValueEvidence: true}
	service := newVirtualReportService(&virtualReportPermissionChecker{deniedField: "QueueId"})
	registration := workItemTimelineRegistration(source)
	registration.Joins[0].Optional = true
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil {
		t.Fatal("optional join without absence-field FLS succeeded, want fail-closed error")
	}
}

func TestVirtualReportSourceOptionalJoinIncludesRequiredProofJoin(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.Columns[2].JoinRef = "ownerRole"
	registration.Joins = []contract.VirtualReportJoin{
		{Name: "owner", ObjectAPIName: "User", SourceFieldAPIName: "OwnerId"},
		{Name: "ownerRole", ObjectAPIName: "UserRole", SourceRecordJoinRef: "owner", SourceFieldAPIName: "UserRoleId", Optional: true},
	}
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	request, _, err := service.buildVirtualReportSourceRequest(&models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, registration, nil, 20, 0)
	if err != nil {
		t.Fatalf("buildVirtualReportSourceRequest: %v", err)
	}
	if len(request.Joins) != 2 || request.Joins[0].Name != "owner" || request.Joins[1].Name != "ownerRole" {
		t.Fatalf("requested joins = %#v, want required owner plus optional ownerRole", request.Joins)
	}
}

func TestVirtualReportSourceRejectsOptionalJoinWithoutNullEvidence(t *testing.T) {
	source := &workItemTimelineSource{omitJoinAccessEvidence: true}
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(source)
	registration.Joins[0].Optional = true
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil {
		t.Fatal("optional join with detached value evidence succeeded, want fail-closed error")
	}
}

func TestVirtualReportSourceRejectsDeniedPresentOptionalJoin(t *testing.T) {
	source := &workItemTimelineSource{}
	queries := &virtualReportQueryService{omitObject: "Queue"}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := workItemTimelineRegistration(source)
	registration.Joins[0].Optional = true
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"QueueName"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil {
		t.Fatal("RLS-denied present optional join succeeded, want fail-closed error")
	}
}

func TestVirtualReportSourceProjectsAuthoritativeHistoryRows(t *testing.T) {
	oldValue, newValue := "Prospecting", "Qualification"
	queries := &virtualReportQueryService{historyRows: []contract.HistoryRecord{
		{ID: "history-2", ParentID: "work-00", Field: "Status", OldValue: &oldValue, NewValue: &newValue, CreatedDate: "2026-07-03T00:00:00Z"},
	}}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := contract.VirtualReportSourceRegistration{
		SourceRef:                "WorkItemHistory",
		ParentObjectAPIName:      "WorkItem",
		RowFieldSecurityRequired: true,
		Capabilities:             contract.VirtualReportSourceCapabilities{Pagination: true},
		Columns: []contract.VirtualReportColumn{
			{Name: "OldValue"},
			{Name: "ChangedAt"},
		},
		Source: &staticVirtualReportSource{result: &contract.VirtualReportSourceResult{TotalCount: 1, Rows: []contract.VirtualReportRow{{
			HistoryRecordID: "history-2",
			AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
			Values: map[string]contract.VirtualReportValue{
				"OldValue":  {History: &contract.VirtualReportHistoryProjection{RecordID: "history-2", Field: contract.VirtualReportHistoryOldValue}},
				"ChangedAt": {History: &contract.VirtualReportHistoryProjection{RecordID: "history-2", Field: contract.VirtualReportHistoryCreatedDate}},
			},
		}}}},
	}
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	result, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemHistory",
		Columns:   []string{"OldValue", "ChangedAt"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
	if err != nil {
		t.Fatalf("RunReportDefinitionPage: %v", err)
	}
	if len(result.Rows) != 1 || result.Rows[0]["OldValue"] != oldValue || result.Rows[0]["ChangedAt"] != "2026-07-03T00:00:00Z" {
		t.Fatalf("history result = %#v", result.Rows)
	}
	if queries.historyCalls != 1 {
		t.Fatalf("history authority calls = %d, want 1", queries.historyCalls)
	}
}

func TestVirtualReportSourceProjectsDerivedHistoryEvidence(t *testing.T) {
	oldStatus, newStatus := "open", "closed"
	newScore := "20"
	queries := &virtualReportQueryService{historyRows: []contract.HistoryRecord{
		{ID: "status-1", ParentID: "work-00", Field: "Status", OldValue: &oldStatus, NewValue: &newStatus, CreatedDate: "2026-07-01T00:00:00Z"},
		{ID: "score-1", ParentID: "work-00", Field: "Score", NewValue: &newScore, CreatedDate: "2026-07-02T00:00:00Z"},
		{ID: "status-2", ParentID: "work-00", Field: "Status", OldValue: &oldStatus, NewValue: &newStatus, CreatedDate: "2026-07-03T00:00:00Z"},
	}}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := contract.VirtualReportSourceRegistration{
		SourceRef:                "WorkItemHistory",
		ParentObjectAPIName:      "WorkItem",
		RowFieldSecurityRequired: true,
		Capabilities: contract.VirtualReportSourceCapabilities{
			Derived: true, Pagination: true,
		},
		Columns: []contract.VirtualReportColumn{
			{Name: "SnapshotScore", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Score"}}},
			{Name: "StatusDuration", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}, Deriver: elapsedDaysVirtualReportDeriver{}},
		},
		Source: &staticVirtualReportSource{result: &contract.VirtualReportSourceResult{TotalCount: 1, Rows: []contract.VirtualReportRow{{
			HistoryRecordID: "status-2",
			AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
			Values: map[string]contract.VirtualReportValue{
				"SnapshotScore": {History: &contract.VirtualReportHistoryProjection{RecordID: "score-1", Field: contract.VirtualReportHistoryNewValue}},
				"StatusDuration": {HistoryInputs: []contract.VirtualReportHistoryProjection{
					{RecordID: "status-2", Field: contract.VirtualReportHistoryCreatedDate},
					{RecordID: "status-1", Field: contract.VirtualReportHistoryCreatedDate},
				}},
			},
		}}}},
	}
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	result, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemHistory", Columns: []string{"SnapshotScore", "StatusDuration"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
	if err != nil {
		t.Fatalf("RunReportDefinitionPage: %v", err)
	}
	if len(result.Rows) != 1 || result.Rows[0]["SnapshotScore"] != newScore || result.Rows[0]["StatusDuration"] != float64(2) {
		t.Fatalf("derived history result = %#v", result.Rows)
	}
	if queries.historyCalls != 1 {
		t.Fatalf("history authority calls = %d, want one batched reload", queries.historyCalls)
	}
}

func TestVirtualReportSourceProjectsNilElapsedWithoutPreviousEvidence(t *testing.T) {
	queries := &virtualReportQueryService{historyRows: []contract.HistoryRecord{{
		ID: "status-1", ParentID: "work-00", Field: "Status", CreatedDate: "2026-07-01T00:00:00Z",
	}}}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := contract.VirtualReportSourceRegistration{
		SourceRef:                "WorkItemHistory",
		ParentObjectAPIName:      "WorkItem",
		RowFieldSecurityRequired: true,
		Capabilities:             contract.VirtualReportSourceCapabilities{Derived: true, Pagination: true},
		Columns: []contract.VirtualReportColumn{{
			Name: "StatusDuration", Derived: true,
			FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}},
			Deriver:         elapsedDaysVirtualReportDeriver{},
		}},
		Source: &staticVirtualReportSource{result: &contract.VirtualReportSourceResult{TotalCount: 1, Rows: []contract.VirtualReportRow{{
			HistoryRecordID: "status-1",
			AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
			Values: map[string]contract.VirtualReportValue{
				"StatusDuration": {HistoryInputs: []contract.VirtualReportHistoryProjection{{RecordID: "status-1", Field: contract.VirtualReportHistoryCreatedDate}}},
			},
		}}}},
	}
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	result, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemHistory", Columns: []string{"StatusDuration"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
	if err != nil {
		t.Fatalf("RunReportDefinitionPage: %v", err)
	}
	if len(result.Rows) != 1 || result.Rows[0]["StatusDuration"] != nil {
		t.Fatalf("first elapsed history result = %#v, want nil duration", result.Rows)
	}
}

func TestVirtualReportSourceRejectsInvalidDerivedHistoryEvidence(t *testing.T) {
	value := "value"
	for _, test := range []struct {
		name      string
		column    contract.VirtualReportColumn
		value     contract.VirtualReportValue
		history   []contract.HistoryRecord
		wantError string
	}{
		{
			name:      "off-anchor projection without static FLS dependency",
			column:    contract.VirtualReportColumn{Name: "Value", Derived: true},
			value:     contract.VirtualReportValue{History: &contract.VirtualReportHistoryProjection{RecordID: "other", Field: contract.VirtualReportHistoryNewValue}},
			wantError: "off-anchor history projection requires a declared FLS dependency",
		},
		{
			name:      "history inputs on non-derived column",
			column:    contract.VirtualReportColumn{Name: "Value", FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}},
			value:     contract.VirtualReportValue{HistoryInputs: []contract.VirtualReportHistoryProjection{{RecordID: "anchor", Field: contract.VirtualReportHistoryCreatedDate}}},
			wantError: "history inputs require a registered derived column",
		},
		{
			name:      "history inputs without registered deriver",
			column:    contract.VirtualReportColumn{Name: "Value", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}},
			value:     contract.VirtualReportValue{HistoryInputs: []contract.VirtualReportHistoryProjection{{RecordID: "anchor", Field: contract.VirtualReportHistoryCreatedDate}}},
			wantError: "history inputs require a registered derived column",
		},
		{
			name:   "derived record from another parent",
			column: contract.VirtualReportColumn{Name: "Value", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}},
			value:  contract.VirtualReportValue{History: &contract.VirtualReportHistoryProjection{RecordID: "other", Field: contract.VirtualReportHistoryNewValue}},
			history: []contract.HistoryRecord{
				{ID: "anchor", ParentID: "work-00", Field: "Status", NewValue: &value},
				{ID: "other", ParentID: "work-99", Field: "Status", NewValue: &value},
			},
			wantError: "permission denied",
		},
		{
			name:   "derived input from another parent",
			column: contract.VirtualReportColumn{Name: "Value", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}, Deriver: elapsedDaysVirtualReportDeriver{}},
			value: contract.VirtualReportValue{HistoryInputs: []contract.VirtualReportHistoryProjection{
				{RecordID: "anchor", Field: contract.VirtualReportHistoryCreatedDate},
				{RecordID: "previous", Field: contract.VirtualReportHistoryCreatedDate},
			}},
			history: []contract.HistoryRecord{
				{ID: "anchor", ParentID: "work-00", Field: "Status", CreatedDate: "2026-07-02T00:00:00Z"},
				{ID: "previous", ParentID: "work-99", Field: "Status", CreatedDate: "2026-07-01T00:00:00Z"},
			},
			wantError: "permission denied",
		},
		{
			name:   "derived input outside declared FLS dependency",
			column: contract.VirtualReportColumn{Name: "Value", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}, Deriver: elapsedDaysVirtualReportDeriver{}},
			value: contract.VirtualReportValue{HistoryInputs: []contract.VirtualReportHistoryProjection{
				{RecordID: "anchor", Field: contract.VirtualReportHistoryCreatedDate},
				{RecordID: "score", Field: contract.VirtualReportHistoryCreatedDate},
			}},
			history: []contract.HistoryRecord{
				{ID: "anchor", ParentID: "work-00", Field: "Status", CreatedDate: "2026-07-02T00:00:00Z"},
				{ID: "score", ParentID: "work-00", Field: "Score", CreatedDate: "2026-07-01T00:00:00Z"},
			},
			wantError: "history field is not a declared FLS dependency",
		},
		{
			name:   "product deriver failure",
			column: contract.VirtualReportColumn{Name: "Value", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}, Deriver: elapsedDaysVirtualReportDeriver{}},
			value: contract.VirtualReportValue{HistoryInputs: []contract.VirtualReportHistoryProjection{
				{RecordID: "anchor", Field: contract.VirtualReportHistoryCreatedDate},
				{RecordID: "previous", Field: contract.VirtualReportHistoryCreatedDate},
			}},
			history: []contract.HistoryRecord{
				{ID: "anchor", ParentID: "work-00", Field: "Status", CreatedDate: "2026-07-01T00:00:00Z"},
				{ID: "previous", ParentID: "work-00", Field: "Status", CreatedDate: "2026-07-02T00:00:00Z"},
			},
			wantError: "derived value calculation failed",
		},
	} {
		t.Run(test.name, func(t *testing.T) {
			queries := &virtualReportQueryService{historyRows: test.history}
			service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
			registration := contract.VirtualReportSourceRegistration{
				SourceRef: "WorkItemHistory", ParentObjectAPIName: "WorkItem", RowFieldSecurityRequired: true,
				Capabilities: contract.VirtualReportSourceCapabilities{Derived: true, Pagination: true},
				Columns:      []contract.VirtualReportColumn{test.column},
				Source: &staticVirtualReportSource{result: &contract.VirtualReportSourceResult{TotalCount: 1, Rows: []contract.VirtualReportRow{{
					HistoryRecordID: "anchor",
					AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
					Values:          map[string]contract.VirtualReportValue{"Value": test.value},
				}}}},
			}
			if err := service.RegisterVirtualReportSource(registration); err != nil {
				t.Fatalf("RegisterVirtualReportSource: %v", err)
			}
			_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
				SourceRef: "WorkItemHistory", Columns: []string{"Value"},
			}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
			if err == nil || !strings.Contains(err.Error(), test.wantError) {
				t.Fatalf("error = %v, want substring %q", err, test.wantError)
			}
		})
	}
}

type elapsedDaysVirtualReportDeriver struct{}

func (elapsedDaysVirtualReportDeriver) DeriveVirtualReportValue(inputs []interface{}) (interface{}, error) {
	if len(inputs) == 1 {
		return nil, nil
	}
	if len(inputs) != 2 {
		return nil, fmt.Errorf("expected current and previous timestamps")
	}
	current, err := time.Parse(time.RFC3339Nano, fmt.Sprint(inputs[0]))
	if err != nil {
		return nil, err
	}
	previous, err := time.Parse(time.RFC3339Nano, fmt.Sprint(inputs[1]))
	if err != nil {
		return nil, err
	}
	if current.Before(previous) {
		return nil, fmt.Errorf("negative elapsed duration")
	}
	return current.Sub(previous).Hours() / 24, nil
}

func TestVirtualReportSourceRejectsMetadataOnlyHistoryPayload(t *testing.T) {
	oldValue := "hidden"
	queries := &virtualReportQueryService{historyRows: []contract.HistoryRecord{{
		ID: "history-1", ParentID: "work-00", Field: "Status", OldValue: &oldValue,
	}}}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	registration := contract.VirtualReportSourceRegistration{
		SourceRef:                "WorkItemHistory",
		ParentObjectAPIName:      "WorkItem",
		RowFieldSecurityRequired: true,
		Capabilities:             contract.VirtualReportSourceCapabilities{Pagination: true},
		Columns:                  []contract.VirtualReportColumn{{Name: "Id", MetadataOnly: true}},
		Source: &staticVirtualReportSource{result: &contract.VirtualReportSourceResult{Rows: []contract.VirtualReportRow{{
			HistoryRecordID: "history-1",
			AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
			Values: map[string]contract.VirtualReportValue{
				"Id": {History: &contract.VirtualReportHistoryProjection{RecordID: "history-1", Field: contract.VirtualReportHistoryOldValue}},
			},
		}}}},
	}
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemHistory", Columns: []string{"Id"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil {
		t.Fatal("metadata-only history payload succeeded, want fail-closed error")
	}
}

func TestVirtualReportSourceRejectsHistoryFromAnotherParent(t *testing.T) {
	oldValue := "open"
	queries := &virtualReportQueryService{historyRows: []contract.HistoryRecord{{
		ID: "history-1", ParentID: "work-99", Field: "Status", OldValue: &oldValue,
	}}}
	service := NewReportService(queries, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
	column := contract.VirtualReportColumn{Name: "OldValue"}
	_, err := service.authorizeVirtualReportRows(
		context.Background(),
		contract.VirtualReportSourceRegistration{ParentObjectAPIName: "WorkItem", RowFieldSecurityRequired: true},
		nil,
		map[string]contract.VirtualReportColumn{"oldvalue": column},
		[]contract.VirtualReportRow{{
			HistoryRecordID: "history-1",
			AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
			Values: map[string]contract.VirtualReportValue{
				"OldValue": {History: &contract.VirtualReportHistoryProjection{RecordID: "history-1", Field: contract.VirtualReportHistoryOldValue}},
			},
		}},
		&models.UserSession{ID: "user-1"},
	)
	if err == nil {
		t.Fatal("history row from another parent succeeded, want fail-closed error")
	}
}

func TestVirtualReportSourceRejectsHistoryProjectionWithoutMatchingRow(t *testing.T) {
	for _, test := range []struct {
		name             string
		historyRecordID  string
		projectionRecord string
		wantError        string
	}{
		{name: "missing row id", projectionRecord: "history-1", wantError: "internal error: virtual report history projection is incomplete"},
		{name: "missing projection id", historyRecordID: "history-1", wantError: "internal error: virtual report history projection is incomplete"},
		{name: "different row id", historyRecordID: "history-1", projectionRecord: "history-2", wantError: "internal error: virtual report history projection does not match its row"},
	} {
		t.Run(test.name, func(t *testing.T) {
			service := NewReportService(&virtualReportQueryService{}, virtualReportMetadata{}, &virtualReportPermissionChecker{}, nil)
			column := contract.VirtualReportColumn{Name: "OldValue"}
			_, err := service.authorizeVirtualReportRows(
				context.Background(),
				contract.VirtualReportSourceRegistration{ParentObjectAPIName: "WorkItem", RowFieldSecurityRequired: true},
				nil,
				map[string]contract.VirtualReportColumn{"oldvalue": column},
				[]contract.VirtualReportRow{{
					HistoryRecordID: test.historyRecordID,
					AccessRecords:   []contract.VirtualReportAccessRecord{{ObjectAPIName: "WorkItem", RecordID: "work-00"}},
					Values: map[string]contract.VirtualReportValue{
						"OldValue": {History: &contract.VirtualReportHistoryProjection{RecordID: test.projectionRecord, Field: contract.VirtualReportHistoryOldValue}},
					},
				}},
				&models.UserSession{ID: "user-1"},
			)
			if err == nil || err.Error() != test.wantError {
				t.Fatalf("error = %v, want %q", err, test.wantError)
			}
		})
	}
}

type staticVirtualReportSource struct {
	result *contract.VirtualReportSourceResult
}

func (s *staticVirtualReportSource) Execute(context.Context, contract.VirtualReportSourceRequest, *models.UserSession) (*contract.VirtualReportSourceResult, error) {
	return s.result, nil
}

func TestVirtualReportSourceRegistrationRejectsDuplicates(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	if err := service.RegisterVirtualReportSource(registration); err != nil {
		t.Fatalf("first registration: %v", err)
	}
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("duplicate registration succeeded, want conflict")
	}
}

func TestVirtualReportSourceRegistrationRejectsPhysicalObjectCollision(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.SourceRef = "Account"
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("physical object source collision succeeded, want conflict")
	}
}

func TestVirtualReportSourceRegistrationRejectsPhysicalObjectAliasCollision(t *testing.T) {
	standardObjects := &StandardObjectResolver{
		canonical: map[string]string{"orderitem": "orderitem"},
		aliases:   map[string]string{"ORDERITEMLIST": "orderitem"},
	}
	service := newVirtualReportService(&virtualReportPermissionChecker{}, WithStandardObjectResolver(standardObjects))
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.SourceRef = "OrderItemList"
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("physical object alias collision succeeded, want conflict")
	}
}

func TestVirtualReportSourceRegistrationRejectsSyntheticCRTCollision(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.SourceRef = "CustomEntity$WorkItem"
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("synthetic CRT source collision succeeded, want conflict")
	}
}

func TestVirtualReportSourceRegistrationRejectsDuplicateFieldDependency(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.Columns[1].FieldReferences = append(registration.Columns[1].FieldReferences, registration.Columns[1].FieldReferences[0])
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("duplicate field dependency succeeded, want conflict")
	}
}

func TestVirtualReportSourceRegistrationRejectsJoinWithoutRelationshipField(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.Joins[0].SourceFieldAPIName = ""
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("join without relationship field succeeded, want fail-closed error")
	}
}

func TestVirtualReportSourceRegistrationRejectsDeriverOnNonDerivedColumn(t *testing.T) {
	service := newVirtualReportService(&virtualReportPermissionChecker{})
	registration := workItemTimelineRegistration(&workItemTimelineSource{})
	registration.Columns[1].Deriver = elapsedDaysVirtualReportDeriver{}
	if err := service.RegisterVirtualReportSource(registration); err == nil {
		t.Fatal("deriver on non-derived column succeeded, want conflict")
	}
}

func TestVirtualReportSourceExecutionRejectsStoredCRTCollision(t *testing.T) {
	resolver := &virtualReportCRTResolver{}
	source := &workItemTimelineSource{}
	service := newVirtualReportService(&virtualReportPermissionChecker{}, WithCRTResolver(resolver))
	if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"Id", "Status", "QueueName", "AgeDays"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err == nil {
		t.Fatal("stored CRT source collision succeeded, want conflict")
	}
	if resolver.calls != 1 {
		t.Fatalf("CRT resolver calls = %d, want 1 conflict check", resolver.calls)
	}
	if source.calls != 0 {
		t.Fatalf("source calls = %d, want 0", source.calls)
	}
}

func TestVirtualReportSourceExecutionAcceptsMatchingStoredBinding(t *testing.T) {
	repository := &bindingCRTRepository{byName: map[string]*models.SystemReportType{
		"WorkItemTimeline": {
			FullName: "WorkItemTimeline",
			Metadata: `{"virtualSource":{"sourceRef":"WorkItemTimeline","configuration":{}}}`,
		},
	}}
	resolver := newCRTResolverForTest(repository, nil, nil, nil)
	source := &workItemTimelineSource{}
	service := newVirtualReportService(&virtualReportPermissionChecker{}, WithCRTResolver(resolver))
	if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	if _, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"Id", "Status"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0); err != nil {
		t.Fatalf("RunReportDefinitionPage: %v", err)
	}
	if repository.loadByNameCalls != 1 {
		t.Fatalf("CRT repository calls = %d, want 1", repository.loadByNameCalls)
	}
	if source.calls != 1 {
		t.Fatalf("source calls = %d, want 1", source.calls)
	}
}

func TestVirtualReportSourceExecutionRejectsUnregisteredStoredBinding(t *testing.T) {
	repository := &bindingCRTRepository{byName: map[string]*models.SystemReportType{
		"WorkItemTimeline": {
			FullName: "WorkItemTimeline",
			Metadata: `{"virtualSource":{"sourceRef":"WorkItemTimeline","configuration":{}}}`,
		},
	}}
	resolver := newCRTResolverForTest(repository, nil, nil, nil)
	service := newVirtualReportService(&virtualReportPermissionChecker{}, WithCRTResolver(resolver))
	_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"Id"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
	if err == nil || !strings.Contains(err.Error(), "unregistered virtual report source") {
		t.Fatalf("unregistered binding error = %v", err)
	}
	if repository.loadByNameCalls != 1 {
		t.Fatalf("CRT repository calls = %d, want 1", repository.loadByNameCalls)
	}
}

func TestVirtualReportSourceExecutionRejectsMalformedStoredBindingRegardlessOfKeyOrder(t *testing.T) {
	metadata := map[string]string{
		"literal binding after malformed sibling":         `{"broken":,"virtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"literal binding before malformed sibling":        `{"virtualSource":{"sourceRef":"WorkItemTimeline"},"broken":}`,
		"escaped binding after malformed sibling":         `{"broken":,"\u0076irtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"escaped binding before malformed sibling":        `{"\u0076irtualSource":{"sourceRef":"WorkItemTimeline"},"broken":}`,
		"literal binding after mismatched root closer":    `{"broken":],"virtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"literal binding before mismatched root closer":   `{"virtualSource":{"sourceRef":"WorkItemTimeline"},"broken":]}`,
		"escaped binding after mismatched root closer":    `{"broken":],"\u0076irtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"escaped binding before mismatched root closer":   `{"\u0076irtualSource":{"sourceRef":"WorkItemTimeline"},"broken":]}`,
		"literal binding after mismatched nested closer":  `{"broken":[},"value"],"virtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"literal binding before mismatched nested closer": `{"virtualSource":{"sourceRef":"WorkItemTimeline"},"broken":[}]}`,
		"escaped binding after mismatched nested closer":  `{"broken":[},"value"],"\u0076irtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"escaped binding before mismatched nested closer": `{"\u0076irtualSource":{"sourceRef":"WorkItemTimeline"},"broken":[}]}`,
		"literal binding after missing separator":         `{"broken":true "virtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"escaped binding after missing separator":         `{"broken":true "\u0076irtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"literal binding after invalid separator":         `{"broken":true @ "virtualSource":{"sourceRef":"WorkItemTimeline"}}`,
		"escaped binding after invalid separator":         `{"broken":true @ "\u0076irtualSource":{"sourceRef":"WorkItemTimeline"}}`,
	}
	for name, value := range metadata {
		t.Run(name, func(t *testing.T) {
			repository := &bindingCRTRepository{byName: map[string]*models.SystemReportType{
				"WorkItemTimeline": {FullName: "WorkItemTimeline", Metadata: value},
			}}
			resolver := newCRTResolverForTest(repository, nil, nil, nil)
			service := newVirtualReportService(&virtualReportPermissionChecker{}, WithCRTResolver(resolver))
			_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
				SourceRef: "WorkItemTimeline",
				Columns:   []string{"Id"},
			}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
			if err == nil || !strings.Contains(err.Error(), "invalid metadata JSON") {
				t.Fatalf("malformed binding error = %v", err)
			}
			if repository.loadByNameCalls != 1 {
				t.Fatalf("CRT repository calls = %d, want 1", repository.loadByNameCalls)
			}
		})
	}
}

func TestVirtualReportSourceExecutionDoesNotPromoteMalformedNestedBinding(t *testing.T) {
	for name, metadata := range map[string]string{
		"literal": `{"outer":[},"virtualSource":{"sourceRef":"Nested"}}]}`,
		"escaped": `{"outer":[},"\u0076irtualSource":{"sourceRef":"Nested"}}]}`,
	} {
		t.Run(name, func(t *testing.T) {
			repository := &bindingCRTRepository{byName: map[string]*models.SystemReportType{
				"PhysicalReport": {FullName: "PhysicalReport", BaseObject: "Account", Metadata: metadata},
			}}
			resolver := newCRTResolverForTest(repository, nil, nil, nil)
			if _, _, err := resolver.Resolve(context.Background(), "PhysicalReport", nil); err != nil {
				t.Fatalf("Resolve physical CRT: %v", err)
			}
			if repository.loadByNameCalls != 1 {
				t.Fatalf("repository calls = %d, want 1", repository.loadByNameCalls)
			}
		})
	}
}

func TestVirtualReportSourceExecutionRejectsUnboundStoredReportTypeWithOneLookup(t *testing.T) {
	resolver := &virtualReportBindingCRTResolver{reportTypeExists: true}
	source := &workItemTimelineSource{}
	service := newVirtualReportService(&virtualReportPermissionChecker{}, WithCRTResolver(resolver))
	if err := service.RegisterVirtualReportSource(workItemTimelineRegistration(source)); err != nil {
		t.Fatalf("RegisterVirtualReportSource: %v", err)
	}
	_, err := service.RunReportDefinitionPage(context.Background(), &models.ReportDefinition{
		SourceRef: "WorkItemTimeline",
		Columns:   []string{"Id"},
	}, &models.UserSession{ID: "user-1"}, nil, 20, 0)
	if err == nil || !strings.Contains(err.Error(), "conflicts with a custom report type") {
		t.Fatalf("unbound stored report type error = %v", err)
	}
	if resolver.bindingCalls != 1 || resolver.resolveCalls != 0 {
		t.Fatalf("resolver calls = binding %d, CRT %d", resolver.bindingCalls, resolver.resolveCalls)
	}
	if source.calls != 0 {
		t.Fatalf("source calls = %d, want 0", source.calls)
	}
}

type virtualReportCRTResolver struct{ calls int }

func (r *virtualReportCRTResolver) Resolve(context.Context, string, *models.UserSession) (*JoinTemplate, []CRTWarning, error) {
	r.calls++
	return &JoinTemplate{PrimaryTable: "dead_physical_source"}, nil, nil
}

type virtualReportBindingCRTResolver struct {
	bound            bool
	reportTypeExists bool
	bindingCalls     int
	resolveCalls     int
}

func (r *virtualReportBindingCRTResolver) Resolve(context.Context, string, *models.UserSession) (*JoinTemplate, []CRTWarning, error) {
	r.resolveCalls++
	return &JoinTemplate{PrimaryTable: "dead_physical_source"}, nil, nil
}

func (r *virtualReportBindingCRTResolver) ResolveVirtualReportSourceBinding(_ context.Context, sourceRef string, _ *models.UserSession) (VirtualReportSourceBinding, bool, bool, error) {
	r.bindingCalls++
	return VirtualReportSourceBinding{SourceRef: sourceRef, Configuration: []byte(`{}`)}, r.bound, r.reportTypeExists, nil
}

func workItemTimelineRegistration(source contract.VirtualReportSource) contract.VirtualReportSourceRegistration {
	return contract.VirtualReportSourceRegistration{
		SourceRef:                "WorkItemTimeline",
		ParentObjectAPIName:      "WorkItem",
		RowFieldSecurityRequired: true,
		Capabilities: contract.VirtualReportSourceCapabilities{
			Filters:    true,
			Grouping:   true,
			Joins:      true,
			Derived:    true,
			Pagination: true,
		},
		Columns: []contract.VirtualReportColumn{
			{Name: "Id", MetadataOnly: true},
			{Name: "Status", FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "Status"}}},
			{Name: "QueueName", JoinRef: "queue", FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "Queue", FieldAPIName: "Name"}}},
			{Name: "AgeDays", Derived: true, FieldReferences: []contract.VirtualReportFieldReference{{ObjectAPIName: "WorkItem", FieldAPIName: "AgeDays"}}},
		},
		Joins:  []contract.VirtualReportJoin{{Name: "queue", ObjectAPIName: "Queue", SourceFieldAPIName: "QueueId"}},
		Source: source,
	}
}

type workItemTimelineSource struct {
	request                contract.VirtualReportSourceRequest
	calls                  int
	omitAccessEvidence     bool
	omitJoinAccessEvidence bool
	omitJoinValueEvidence  bool
	omitRowFieldEvidence   bool
	waitForCancellation    bool
	rowFieldObject         string
	recordFieldOverride    string
	entered                chan struct{}
}

func (s *workItemTimelineSource) Execute(ctx context.Context, request contract.VirtualReportSourceRequest, _ *models.UserSession) (*contract.VirtualReportSourceResult, error) {
	s.calls++
	s.request = request
	if s.waitForCancellation {
		close(s.entered)
		<-ctx.Done()
		return nil, ctx.Err()
	}
	statusFilter := ""
	for _, filter := range request.Definition.Filters {
		if filter.Column == "Status" && (filter.Operator == "equals" || filter.Operator == "=") {
			statusFilter = filter.Value
		}
	}
	if value, ok := request.RuntimeFilters["Status"]; ok {
		statusFilter = fmt.Sprint(value)
	}
	rows := make([]contract.VirtualReportRow, 0, 60)
	rowFieldObject := s.rowFieldObject
	if rowFieldObject == "" {
		rowFieldObject = "WorkItem"
	}
	for i := 0; i < 60; i++ {
		status := "closed"
		if i%2 == 0 {
			status = "open"
		}
		if statusFilter != "" && status != statusFilter {
			continue
		}
		var rowFieldReference *contract.VirtualReportFieldReference
		if !s.omitRowFieldEvidence {
			rowFieldReference = &contract.VirtualReportFieldReference{ObjectAPIName: rowFieldObject, FieldAPIName: "Status"}
		}
		row := contract.VirtualReportRow{
			Values: make(map[string]contract.VirtualReportValue, len(request.Columns)),
		}
		needsQueue := false
		for _, column := range request.Columns {
			value := contract.VirtualReportValue{
				AccessObjectAPIName: "WorkItem",
				RowFieldReference:   rowFieldReference,
			}
			switch column.Name {
			case "Id":
				value.RecordFieldName = "Id"
			case "Status":
				value.RecordFieldName = "Status"
				if s.recordFieldOverride != "" {
					value.RecordFieldName = s.recordFieldOverride
				}
			case "QueueName":
				if s.omitJoinValueEvidence {
					value = contract.VirtualReportValue{}
				} else {
					value.AccessObjectAPIName = "Queue"
					value.RecordFieldName = "Name"
					needsQueue = true
				}
			case "AgeDays":
				value.RecordFieldName = "AgeDays"
			}
			row.Values[column.Name] = value
		}
		if !s.omitAccessEvidence {
			row.AccessRecords = []contract.VirtualReportAccessRecord{{
				ObjectAPIName: "WorkItem",
				RecordID:      fmt.Sprintf("work-%02d", i),
			}}
			if needsQueue && !s.omitJoinAccessEvidence {
				row.AccessRecords = append(row.AccessRecords, contract.VirtualReportAccessRecord{
					ObjectAPIName: "Queue",
					RecordID:      fmt.Sprintf("queue-%02d", i),
				})
			}
		}
		rows = append(rows, row)
	}
	start := request.Offset
	if start > len(rows) {
		start = len(rows)
	}
	end := start + request.Limit
	if end > len(rows) {
		end = len(rows)
	}
	return &contract.VirtualReportSourceResult{TotalCount: len(rows), Rows: rows[start:end]}, nil
}

type virtualReportMetadata struct{ MetadataSource }

func (virtualReportMetadata) GetSchema(_ context.Context, apiName string) *models.ObjectMetadata {
	switch apiName {
	case "WorkItem", "Queue", "Account":
		return &models.ObjectMetadata{APIName: apiName}
	default:
		return nil
	}
}

func newVirtualReportService(permissions PermissionChecker, opts ...ReportServiceOption) *ReportService {
	return NewReportService(&virtualReportQueryService{}, virtualReportMetadata{}, permissions, nil, opts...)
}

type virtualReportQueryService struct {
	ports.QueryService
	omitObject            string
	omitParentQueueID     bool
	parentQueueIDOverride string
	calls                 int
	historyRows           []contract.HistoryRecord
	historyCalls          int
}

func (s *virtualReportQueryService) QueryHistory(_ context.Context, request contract.HistoryQueryRequest, _ *models.UserSession) (*contract.HistoryQueryResult, error) {
	s.historyCalls++
	requested := make(map[string]struct{})
	if request.Filter.Kind == queryspec.PredicateFieldComparison && request.Filter.Field == "Id" && request.Filter.Op == "IN" {
		for _, id := range request.Filter.Value.([]string) {
			requested[id] = struct{}{}
		}
	}
	rows := make([]contract.HistoryRecord, 0, len(requested))
	for _, row := range s.historyRows {
		if _, ok := requested[row.ID]; ok {
			rows = append(rows, row)
		}
	}
	return &contract.HistoryQueryResult{TotalSize: len(rows), Done: true, Rows: rows}, nil
}

func (s *virtualReportQueryService) QueryWithSpec(_ context.Context, request queryspec.QuerySpec, _ *models.UserSession) (*models.QueryResult, error) {
	s.calls++
	if request.ObjectAPIName == s.omitObject {
		return &models.QueryResult{}, nil
	}
	ids, _ := request.Filter.Value.([]string)
	records := make([]models.SObject, 0, len(ids))
	for _, id := range ids {
		var i int
		_, _ = fmt.Sscanf(id, "work-%02d", &i)
		_, _ = fmt.Sscanf(id, "queue-%02d", &i)
		switch request.ObjectAPIName {
		case "WorkItem":
			status := "closed"
			if i%2 == 0 {
				status = "open"
			}
			queueID := fmt.Sprintf("queue-%02d", i)
			if s.omitParentQueueID {
				queueID = ""
			}
			if s.parentQueueIDOverride != "" {
				queueID = s.parentQueueIDOverride
			}
			records = append(records, models.SObject{
				"Id":      id,
				"Status":  status,
				"AgeDays": i,
				"QueueId": queueID,
			})
		case "Queue":
			name := "Support"
			if i%4 == 0 {
				name = "Platform"
			}
			records = append(records, models.SObject{
				"Id":   id,
				"Name": name,
			})
		}
	}
	return &models.QueryResult{Records: records}, nil
}

type virtualReportPermissionChecker struct {
	PermissionChecker
	deniedField string
}

func (*virtualReportPermissionChecker) CheckObjectPermissionWithUser(context.Context, string, string, *models.UserSession) bool {
	return true
}

func (p *virtualReportPermissionChecker) CheckFieldVisibilityWithUser(_ context.Context, _ string, field string, _ *models.UserSession) (bool, error) {
	return p.deniedField == "" || p.deniedField != field, nil
}
