package boundary_test

import (
	"path/filepath"
	"strings"
	"testing"
)

// L0-C / C10 anti-regrowth seal.
//
// PR-C4 flipped the app-blind L0 query engine (nexuscrm-analytics/query_service.go)
// to attach the NEUTRAL child-records slice ([]models.SObject) under a SOQL
// parent-child subquery's relationship name, and to STOP minting the Salesforce
// child-subquery / query wire envelope {"totalSize", "done", "records"}.
//
// The SF child-subquery / query envelope is L1-owned (dialect-sf-crm, which holds
// query.go / query_projection.go). The dialect re-wraps the neutral child-records
// slice into {totalSize, done, records} (wrapChildSubqueryEnvelope), computes the
// top-level {totalSize, done, nextRecordsUrl, records} window, and owns the
// nextRecordsUrl pagination cursor. App-blind L0 speaks the neutral contract
// (neutral []models.SObject child records, contract.QueryResult), never the SF
// wire envelope, so the count below must stay at ZERO.
//
// Markers are deliberately wire-only and precise:
//   - "totalSize" (quoted): the SF query-envelope key. The sole minter was
//     query_service.go's child-subquery envelope, now flipped to a neutral slice.
//     The bare token totalSize is NOT used because it false-positives on the
//     neutral contract.QueryResult.TotalSize struct field, which is a legitimate
//     engine count, not wire skin.
//   - "nextRecordsUrl" (quoted): the SF query-pagination cursor key, an L1-owned
//     wire concept. App-blind L0 must never mint it.
//
// Deliberately NOT sealed: bare done / records. Those tokens are far too generic
// (json struct tags, local variables, the neutral *Records fields) and would
// false-positive across the engine. The two quoted wire keys above are sufficient
// and specific: they are exactly the SF query-envelope keys the engine must not mint.
//
// backend/distributions (L1) is intentionally NOT scanned — that is where the SF
// child-subquery / query wire envelope legitimately lives (the dialect re-wrap).
// Generated Go files and *_test.go files are also excluded. boundarygate does not
// scan backend/, so without this seal the SF query envelope could silently regrow
// in the app-blind L0 surface. This is a count seal pinned at 0, not a ledger: any
// reintroduction is a regression, not a trackable expansion.
var l0QueryWireSkinForbiddenMarkers = []string{
	`"totalSize"`,
	`"nextRecordsUrl"`,
}

func TestAppBlindL0DoesNotEmitSFQueryWireEnvelope(t *testing.T) {
	root := repoRoot(t)

	// App-blind L0 surface. backend/distributions (L1) is deliberately excluded:
	// that is the owner of the SF child-subquery / query wire envelope (the
	// dialect re-wrap). Generated Go files are excluded below.
	l0Dirs := []string{
		"backend/internal",
		"nexuscrm-analytics",
	}

	for _, relDir := range l0Dirs {
		for _, file := range productionGoFilesRecursive(t, filepath.Join(root, relDir)) {
			rel := toRepoRelative(t, root, file)
			body := readFile(t, file)
			if isGeneratedGoFile(body) {
				continue
			}
			for _, marker := range l0QueryWireSkinForbiddenMarkers {
				if n := strings.Count(body, marker); n != 0 {
					t.Errorf("%s emits SF query wire envelope marker %q %d time(s); "+
						"the SF child-subquery / query wire envelope is L1-owned (dialect-sf-crm), "+
						"app-blind L0 must not mint it. Attach the neutral child-records slice "+
						"([]models.SObject) under the relationship name (and speak the neutral "+
						"contract.QueryResult) instead; the dialect re-wraps the SF envelope.", rel, marker, n)
				}
			}
		}
	}
}
