package packs

import (
	"strings"
	"testing"

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

func TestManagedRegistrationSetOwnsSourceValidationSemantics(t *testing.T) {
	managedKind := cp.ComponentKind("managed_test")
	managed := testComponentKindRegistration(managedKind, "ManagedTest")
	managed.Contract.Phase = cp.InstallPlanPhase("object_metadata")
	presentationKind := cp.ComponentKind("presentation_test")
	presentation := cp.ComponentKindRegistration{
		Contract:     cp.ComponentKindContract{Kind: presentationKind},
		Capability:   cp.SourceBackedComponentCapability{Kind: presentationKind, Installable: true},
		BuildHandler: func(cp.ComponentBuildContext, cp.ComponentBuildRequest) error { return nil },
	}
	set, err := NewComponentKindRegistrationSet([]cp.ComponentKindRegistration{managed, presentation})
	if err != nil {
		t.Fatal(err)
	}

	opts := set.withManagedValidationInputs(testPackSourceOptions(t))
	managedPlatformKind := ComponentKind(managedKind)
	if !opts.ComponentKindRegistry.Supports(managedPlatformKind) {
		t.Fatal("managed registration did not supply known-kind validation")
	}
	capability, ok := opts.SourceBackedComponentCapabilities.CapabilityFor(managedPlatformKind)
	if !ok || !capability.Installable || !capability.SupportsManageability(ManageabilityLocked) {
		t.Fatalf("managed capability = %#v, %v", capability, ok)
	}
	if opts.ComponentKindRegistry.Supports(ComponentKind(presentationKind)) {
		t.Fatal("presentation-only registration acquired managed validation semantics")
	}

	components := []ManifestComponent{
		{
			Kind: managedPlatformKind, BusinessKey: "managed", Manageability: ManageabilityLocked,
			Payload: []byte(`{}`), DependsOn: []ComponentReference{{Kind: ComponentKindUIAction, BusinessKey: "later"}},
		},
		{Kind: ComponentKindUIAction, BusinessKey: "later", Manageability: ManageabilityLocked, Payload: []byte(`[]`)},
	}
	diagnostics := validateInstallableSourceBackedPlan(
		&ResolvedPackSource{Manifest: &PackManifest{Name: "managed-validation", Category: AppPack, Components: components}},
		opts, false, false, false, nil, &set,
	)
	phaseDiagnostic := diagnosticWithCode(diagnostics, "component.depends_on.phase_order")
	if phaseDiagnostic == nil || !strings.Contains(phaseDiagnostic.Message, `install phase "object_metadata"`) || !strings.Contains(phaseDiagnostic.Message, `later phase "ui_surfaces"`) {
		t.Fatalf("phase diagnostics = %#v", diagnostics)
	}
	for _, code := range []string{"component.kind.not_installable", "manifest.component.unsupported_for_category"} {
		if diagnosticWithCode(diagnostics, code) != nil {
			t.Fatalf("unexpected %s diagnostics = %#v", code, diagnostics)
		}
	}

	connectorDiagnostics := validateInstallableSourceBackedPlan(
		&ResolvedPackSource{Manifest: &PackManifest{Name: "managed-validation", Category: ConnectorPack, Components: components[:1]}},
		opts, false, false, false, nil, &set,
	)
	if diagnosticWithCode(connectorDiagnostics, "manifest.component.unsupported_for_category") == nil {
		t.Fatalf("category diagnostics = %#v", connectorDiagnostics)
	}

	components[0].Manageability = ManageabilityDefaultsOnly
	manageabilityDiagnostics := validateInstallableSourceBackedPlan(
		&ResolvedPackSource{Manifest: &PackManifest{Name: "managed-validation", Category: AppPack, Components: components[:1]}},
		opts, false, false, false, nil, &set,
	)
	if diagnosticWithCode(manageabilityDiagnostics, "component.manageability.unsupported_for_kind") == nil {
		t.Fatalf("manageability diagnostics = %#v", manageabilityDiagnostics)
	}
}

func diagnosticWithCode(diagnostics []PackDiagnostic, code string) *PackDiagnostic {
	for index := range diagnostics {
		if diagnostics[index].Code == code {
			return &diagnostics[index]
		}
	}
	return nil
}
