// White-box (package packs) DEEP-COMPARE route test for the related_list_rule
// presentation kind in the SF-skin migration.
//
// related_list_rule's internal component stores the RAW req.Payload and sets NO
// expectedProjection (its only authored content surface is the raw payload, which
// the verify closure re-validates). The cp.RelatedListRule declaration is a
// NEUTRAL PROJECTION that DROPS the internal type's Resolution and
// RuntimeAppendOnly fields; the SF corpus declares neither, so the reconstructed
// component is byte-identical. This test builds the related_list_rule component(s)
// BOTH ways — internal dispatch (control) and through the external cp handler
// (routed) — for the SAME SF manifest and asserts FULL equality across the
// exported surface, with a fired-counter guard against a silent no-route
// false-green.
package packs

import (
	"encoding/json"
	"testing"

	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

// fakeRelatedListRuleHandlerFires counts external-handler invocations so the
// deep-compare cannot false-green on a route that silently failed to engage.
var fakeRelatedListRuleHandlerFires int

// fakeRelatedListRuleHandler is the inline contract-only stand-in for the real
// nexuscrm-app-packs provider.go:buildRelatedListRule. It depends ONLY on the cp
// contract package: parse req.Payload into []cp.RelatedListRule and hand it to
// the engine sink.
func fakeRelatedListRuleHandler(ctx cp.ComponentBuildContext, req cp.ComponentBuildRequest) error {
	pctx, ok := ctx.(cp.PresentationComponentBuildContext)
	if !ok {
		return errNotPresentationContext
	}
	var parsed struct {
		Rules []cp.RelatedListRule `json:"rules"`
	}
	if err := json.Unmarshal(req.Payload, &parsed); err != nil {
		return err
	}
	fakeRelatedListRuleHandlerFires++
	return pctx.AddRelatedListRuleComponent(req, parsed.Rules)
}

func relatedListRuleRoutes(t *testing.T, handler cp.ComponentBuildHandler) map[ComponentKind]externalBuildRoute {
	t.Helper()
	routes := newExternalBuildRoutes(
		[]cp.ComponentKindRegistration{{
			Contract:     cp.ComponentKindContract{Kind: cp.ComponentKindRelatedListRule},
			Capability:   cp.SourceBackedComponentCapability{Kind: cp.ComponentKindRelatedListRule, Installable: true},
			BuildHandler: handler,
		}},
		map[ComponentKind]struct{}{ComponentKindRelatedListRule: {}},
	)
	if _, ok := routes[ComponentKindRelatedListRule]; !ok {
		t.Fatalf("expected related_list_rule to be routed externally; install gate dropped it")
	}
	return routes
}

func TestExternalRelatedListRuleRouteDeepCompare(t *testing.T) {
	root := officialAppPacksRootForRouteTest(t)
	if root == "" {
		t.Skip("no nexuscrm-app-packs checkout found; skipping external related_list_rule deep-compare test")
	}
	setupSFRouteTestHost(t)

	routes := relatedListRuleRoutes(t, fakeRelatedListRuleHandler)

	control := buildSFPackForRouteTest(t, root, nil)
	fakeRelatedListRuleHandlerFires = 0
	routed := buildSFPackForRouteTest(t, root, routes)
	if fakeRelatedListRuleHandlerFires == 0 {
		t.Fatalf("external related_list_rule handler never fired; route did not engage (the deep-compare below would be a false-green)")
	}

	controlComps := componentsOfKindForRouteTest(t, control, ComponentKindRelatedListRule)
	routedComps := componentsOfKindForRouteTest(t, routed, ComponentKindRelatedListRule)
	if len(controlComps) == 0 {
		t.Fatalf("no related_list_rule components found in SF pack; nothing to deep-compare")
	}
	if len(controlComps) != len(routedComps) {
		t.Fatalf("related_list_rule component count drift: control=%d routed=%d", len(controlComps), len(routedComps))
	}
	for key, controlComp := range controlComps {
		routedComp, ok := routedComps[key]
		if !ok {
			t.Fatalf("routed pack is missing related_list_rule component %q present in control", key)
		}
		if mismatch := assertRouteComponentsEqual(t, controlComp, routedComp); mismatch != "" {
			t.Errorf("DRIFT: external related_list_rule route is lossy for %q.\n%s", key, mismatch)
		}
	}
}
