package catalogapp

import (
	"bytes"
	"context"
	"encoding/json"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

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

func TestContractConformanceVectorIsConsumedWithoutAnotherDigestImplementation(t *testing.T) {
	var vectors struct {
		Vectors []struct {
			CanonicalManifest string `json:"canonical_manifest"`
			CanonicalBundle   string `json:"canonical_bundle"`
		} `json:"vectors"`
	}
	if err := json.Unmarshal(appauthority.ConformanceVectorsJSON(), &vectors); err != nil {
		t.Fatal(err)
	}
	if len(vectors.Vectors) == 0 {
		t.Fatal("contract contains no conformance vectors")
	}
	for _, vector := range vectors.Vectors {
		manifest, err := appauthority.ParseAppManifest([]byte(vector.CanonicalManifest))
		if err != nil {
			t.Fatal(err)
		}
		if _, err := appauthority.ParseMetadataBundle([]byte(vector.CanonicalBundle), manifest); err != nil {
			t.Fatal(err)
		}
	}
}

func TestCatalogSchemaOwnsOneNonServingAuthority(t *testing.T) {
	joined := strings.Join(SchemaStatementsForTest(), "\n")
	for _, required := range []string{
		"_System_CatalogOrgState", "_System_CatalogPublication", "_System_CatalogPublicationCommand",
		"_System_CatalogPublicationOutcome", "_System_CatalogPublicationHistory",
		"_System_CatalogPublicationActive", "_System_CatalogPublicationCandidate",
		"_System_CatalogAppIdentity", "_System_CatalogAppRelease", "_System_CatalogAppInstallation",
		"_System_CatalogPublisherTrustTransition", "ux_catalog_publisher_transition_epoch",
		"_System_CatalogAppLayoutBundleSlot", "_System_CatalogAppLayoutBundleSlotVersion",
		"_System_CatalogAppReleaseLayoutBundleSlot", "ux_catalog_app_layout_slot_declaration",
		"ux_catalog_app_layout_slot_revision", "idx_catalog_app_release_layout_slot_version",
		"_System_CatalogHandlerBinding", "_System_CatalogFrontendBinding", "_System_CatalogAppOperationJournal",
		"_System_CatalogCRMConversionJournal", "ux_catalog_live_app", "ux_catalog_app_semver",
		"ux_catalog_handler_active", "ActiveAuthorizedWorkloads", "CandidateAuthorizedWorkloads",
		"ActiveResolvedDependencies", "CandidateResolvedDependencies", "_System_CatalogRemovalGateReceipt",
		"CommandKind", "CommandPayloadFormatVersion", "CommandDefinitionRef", "CommandDefinitionVersion",
		"ActiveReleaseDigest", "CandidateReleaseDigest", "chk_catalog_namespace_state",
		"CanonicalizationProfile", "ArtifactMediaType", "AttestationVerifiedAt",
		"AdmissionKind", "SIGNED_PUBLISHER", "STOPPED_SOURCE_NON_PROMOTABLE",
		"_System_CatalogAppReleaseSourceReceipt", "PackageContentDigest", "PromotionDisposition",
		"chk_catalog_app_release_admission", "chk_catalog_app_release_source_disposition",
		"ux_catalog_frontend_staging", "StagingKey", "OperationKey", "chk_catalog_frontend_attempt",
		"chk_catalog_frontend_active_key", "ActivationPredecessorId", "LegacyAuthorityDigest", "MappingVerificationDigest",
		"ux_catalog_crm_operation", "InitiationKind", "chk_catalog_operation_initiation",
		"SelectedHandlerCapabilities", "WorkloadHandlerAdmissions",
	} {
		if !strings.Contains(joined, required) {
			t.Fatalf("Catalog schema is missing %q", required)
		}
	}
	if count := strings.Count(joined, "CREATE TABLE IF NOT EXISTS _System_CatalogOrgState"); count != 1 {
		t.Fatalf("Catalog schema contains %d shared org-writer definitions, want exactly one", count)
	}
	for _, forbidden := range []string{"EndpointUrl", "IssueLease", "_System_RuntimeSecurity", "_System_" + "InstalledPack"} {
		if strings.Contains(joined, forbidden) {
			t.Fatalf("Catalog schema crossed an ownership boundary through %q", forbidden)
		}
	}
	if strings.Contains(joined, "AuthorizedWorkloads JSON NOT NULL") || strings.Contains(joined, "ResolvedDependencies JSON NOT NULL") {
		t.Fatal("installation schema collapsed active and candidate security facts")
	}
	if strings.Contains(joined, "AppId VARCHAR(128) NOT NULL, AppReleaseDigest VARCHAR(71) NOT NULL, State") {
		t.Fatal("namespace authority collapsed active and candidate releases")
	}
	if strings.Contains(joined, "_System_CatalogFrontendBinding") && strings.Contains(joined, "ux_catalog_frontend_natural") {
		t.Fatal("frontend artifact contents became a permanent lifecycle identity")
	}
	for _, statement := range SchemaStatementsForTest() {
		if strings.Contains(statement, "_System_CatalogCRMConversionJournal") &&
			(strings.Contains(statement, "State VARCHAR") || strings.Contains(statement, "Step VARCHAR")) {
			t.Fatal("conversion journal duplicated operation lifecycle state")
		}
	}
	slotTables := 0
	for _, statement := range SchemaStatementsForTest() {
		if !strings.Contains(statement, "CREATE TABLE IF NOT EXISTS _System_CatalogApp") ||
			!strings.Contains(statement, "LayoutBundleSlot") {
			continue
		}
		slotTables++
		for _, forbidden := range []string{"OrgId", "AppInstallationId", "ActiveRelease", "CandidateRelease", "Selected", "Serving"} {
			if strings.Contains(statement, forbidden) {
				t.Fatalf("global App slot registry crossed into installation/publication state through %q", forbidden)
			}
		}
	}
	if slotTables != 3 {
		t.Fatalf("Catalog schema contains %d global App slot tables, want reservation, version ledger, and release binding", slotTables)
	}
}

type nilRuntimeProjectionWriter struct{}

func (*nilRuntimeProjectionWriter) ActivateProjection(context.Context, uint64, RuntimeSecurityProjection) error {
	panic("typed-nil Runtime writer was invoked")
}

func TestProjectionPublisherRejectsTypedNilWriter(t *testing.T) {
	authority := &Authority{}
	var writer *nilRuntimeProjectionWriter
	if err := authority.PublishRuntimeSecurityProjection(context.Background(), "operation", writer); err == nil ||
		!strings.Contains(err.Error(), "writer is required") {
		t.Fatalf("typed-nil writer error = %v", err)
	}
}

func TestProjectionDigestIsOrderIndependentButContentSensitive(t *testing.T) {
	projection := RuntimeSecurityProjection{OrgID: "org-1", RuntimeAudience: "runtime", SecurityEpoch: 4, Bindings: []RuntimeSecurityBinding{
		{OrgID: "org-1", AppInstallationID: "installation-b", CallerWorkloadID: "workload-b", Capabilities: []string{"runtime.b.v1"}, Active: true},
		{OrgID: "org-1", AppInstallationID: "installation-a", CallerWorkloadID: "workload-a", Capabilities: []string{"runtime.a.v1"}, Active: true},
	}}
	first, err := ProjectionDigest(projection)
	if err != nil {
		t.Fatal(err)
	}
	projection.Bindings[0], projection.Bindings[1] = projection.Bindings[1], projection.Bindings[0]
	second, err := ProjectionDigest(projection)
	if err != nil {
		t.Fatal(err)
	}
	if first != second {
		t.Fatalf("binding order changed projection digest: %s != %s", first, second)
	}
	projection.Bindings[0].Capabilities = []string{"runtime.changed.v1"}
	changed, err := ProjectionDigest(projection)
	if err != nil {
		t.Fatal(err)
	}
	if changed == first {
		t.Fatal("projection content change did not change digest")
	}
	projection.Bindings = append(projection.Bindings, projection.Bindings[0])
	if _, err := ProjectionDigest(projection); err == nil {
		t.Fatal("duplicate projection binding was accepted")
	}
}

func TestOperationRequestDigestBindsContinuationIntentWithoutChangingLegacyEmptyShape(t *testing.T) {
	request := BeginOperationRequest{Kind: OperationPrepare, OrgID: "org-test", AppID: "io.example.app"}
	legacyJSON, err := json.Marshal(request)
	if err != nil {
		t.Fatal(err)
	}
	if strings.Contains(string(legacyJSON), "ContinuationIntentDigest") {
		t.Fatalf("empty continuation intent changed the legacy request grammar: %s", legacyJSON)
	}
	legacy, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	request.ContinuationIntentDigest = testDigest("continuation")
	bound, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	if legacy == bound {
		t.Fatal("continuation intent did not change the durable operation request digest")
	}
	request.ContinuationIntentDigest = testDigest("changed")
	changed, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	if changed == bound {
		t.Fatal("changed continuation intent reused the durable operation request digest")
	}
	request.RefreshActiveRelease = true
	refreshed, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	if refreshed == changed {
		t.Fatal("active release refresh mode was absent from durable request identity")
	}
	request.RefreshActiveRelease = false
	request.SelectedHandlerCapabilities = []string{"io.example.issues.read.v1"}
	selected, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	request.SelectedHandlerCapabilities = []string{"io.example.issues.write.v1"}
	selectionChanged, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	if selected == selectionChanged {
		t.Fatal("selected handler capabilities were absent from durable request identity")
	}
	request.WorkloadHandlerAdmissions = []WorkloadHandlerAdmission{{
		CapabilityID: "io.example.issues.read.v1", AuthorizedWorkloadID: "app-service",
		RequiredRuntimeCapabilities: []string{"runtime.records.read.v1"},
	}}
	admitted, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	request.WorkloadHandlerAdmissions[0].AuthorizedWorkloadID = "other-service"
	admissionChanged, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	if admitted == admissionChanged {
		t.Fatal("workload handler admission was absent from durable request identity")
	}
	request.HandlerWorkloadID = "app-service"
	handlerWorkload, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	request.HandlerWorkloadID = "other-service"
	changedHandlerWorkload, err := operationRequestDigest(request)
	if err != nil {
		t.Fatal(err)
	}
	if handlerWorkload != changedHandlerWorkload {
		t.Fatal("handler grant derivation input changed durable request identity independently")
	}
}

func TestLegacyConversionValidationIsCompleteAndNeutral(t *testing.T) {
	release := testReleaseWithHandlerConsumerDependencies(t)
	component := release.Package.Bundle.Components[0]
	legacy := testLegacyInstalledPack("org-1", "legacy-install-1", component)
	legacyAuthorityDigest, err := LegacyAuthorityDigest(legacy)
	if err != nil {
		t.Fatal(err)
	}
	mapping := VerifiedLegacyMapping{LegacyAuthorityDigest: legacyAuthorityDigest, SignerID: "operator.example",
		SignatureVerificationDigest: testDigest("mapping-signature"), AppID: release.AppID,
		TargetReleaseDigest: release.AppReleaseDigest, VerifiedAt: time.Unix(1, 0).UTC(),
		Components: []LegacyComponentMapping{{LegacyComponentKind: "legacy.object.v1", LegacyBusinessKey: "Issue", TargetComponentID: component.ComponentID}}}
	mapping.MappingDigest, err = LegacyMappingDigest(mapping)
	if err != nil {
		t.Fatal(err)
	}
	request := ConversionRequest{Legacy: legacy, Mapping: mapping, Operation: BeginOperationRequest{
		Kind: OperationPrepare, OrgID: legacy.OrgID, AppID: release.AppID, TargetAppReleaseDigest: release.AppReleaseDigest,
		IdempotencyKey: "convert-1", RuntimeAudience: "runtime", AuthorizedWorkloads: []string{"workload-1", "workload-other"},
		GrantedCapabilities: release.Package.Manifest.RequiredEngineCapabilities,
		HandlerWorkloadID:   "workload-1",
	}, HandlerBindings: []HandlerBindingRequest{{CapabilityID: release.Package.Manifest.ProvidedCapabilities[0].CapabilityID,
		HandlerRef: release.Package.Manifest.ProvidedCapabilities[0].HandlerRef, WorkloadID: "workload-1",
		ServiceReleaseDigest: testDigest("service"), CompatibilityReceiptDigest: testDigest("compatibility")}}}
	request.Operation, _, _, err = (&Authority{}).validateBeginOperationForTarget(
		context.Background(), request.Operation, &release, false,
	)
	if err != nil {
		t.Fatal(err)
	}
	if err := validateConversionRequest(request, release); err != nil {
		t.Fatal(err)
	}
	wrongWorkload := request
	wrongWorkload.HandlerBindings = append([]HandlerBindingRequest(nil), request.HandlerBindings...)
	wrongWorkload.HandlerBindings[0].WorkloadID = "workload-other"
	if err := validateConversionRequest(wrongWorkload, release); err == nil ||
		!strings.Contains(err.Error(), "has no") {
		t.Fatalf("consumer-grant-less conversion workload error = %v", err)
	}
	selected := request
	selected.Operation.SelectedHandlerCapabilities = []string{
		release.Package.Manifest.ProvidedCapabilities[0].CapabilityID,
	}
	if err := validateConversionRequest(selected, release); err == nil ||
		!strings.Contains(err.Error(), "does not accept selected handler capabilities") {
		t.Fatalf("selected-handler conversion error = %v", err)
	}
	request.Legacy.DesiredPayloadHash = testDigest("drift")
	if err := validateConversionRequest(request, release); err == nil || !strings.Contains(err.Error(), "converged") {
		t.Fatalf("desired/applied drift error = %v", err)
	}
	request.Legacy.DesiredPayloadHash = request.Legacy.AppliedPayloadHash
	request.Mapping.Components = nil
	request.Mapping.MappingDigest, err = LegacyMappingDigest(request.Mapping)
	if err != nil {
		t.Fatal(err)
	}
	if err := validateConversionRequest(request, release); err == nil || !strings.Contains(err.Error(), "one-to-one") {
		t.Fatalf("partial mapping error = %v", err)
	}
}

func testLegacyInstalledPack(orgID, packInstallID string, component appauthority.Component) LegacyInstalledPack {
	payload := testDigest("legacy-" + packInstallID)
	return LegacyInstalledPack{OrgID: orgID, PackInstallID: packInstallID, PackName: "neutral-app-pack",
		Category: "app", Status: "active", PackVersion: "1.0.0", ManifestFormatVersion: "1",
		PlatformCompatibility: "test", DesiredPayloadHash: payload, AppliedPayloadHash: payload,
		PayloadHashAlgorithm: "sha256", SourceKind: "immutable-artifact", SourceURI: "artifact:neutral-app-pack",
		SourceRevision: "revision-1", HostRequirementsDigest: testDigest("host-requirements"),
		RuntimeDeclarationDigest: testDigest("runtime-declarations"), DeepVerificationDigest: testDigest("deep-verification"),
		Components: []LegacyComponent{{
			ComponentKind: "legacy.object.v1", BusinessKey: component.BusinessKey, ContentDigest: component.ContentDigest,
		}}}
}

func TestUUIDv7GeneratorProducesCanonicalMonotonicTimestampPrefix(t *testing.T) {
	now := time.UnixMilli(1_800_000_000_000).UTC()
	values := make([]string, 16)
	for i := range values {
		value, err := newUUIDv7(now.Add(time.Duration(i) * time.Millisecond))
		if err != nil {
			t.Fatal(err)
		}
		if err := appauthority.ValidateAppInstallationID(value); err != nil {
			t.Fatal(err)
		}
		values[i] = value
	}
	if !sort.StringsAreSorted(values) {
		t.Fatalf("UUIDv7 timestamp order is not lexical: %v", values)
	}
}

func TestCatalogAppHasOnlyReconcileWriterAndAuthorizedConsumerReadPath(t *testing.T) {
	_, file, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("resolve test file")
	}
	packageDir := filepath.Dir(file)
	repoRoot := filepath.Dir(packageDir)
	reconcileDir := filepath.Join(repoRoot, "catalogreconcile")
	reconcileCommandDir := filepath.Join(repoRoot, "cmd", "catalog-reconcile")
	consumerDir := filepath.Join(repoRoot, "catalogconsumer")
	legacyTable := "_System_" + "InstalledPack"
	err := filepath.WalkDir(repoRoot, func(path string, entry os.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if entry.IsDir() {
			if entry.Name() == ".git" {
				return filepath.SkipDir
			}
			return nil
		}
		if filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
			return nil
		}
		raw, err := os.ReadFile(path)
		if err != nil {
			return err
		}
		insideCatalog := path == packageDir || strings.HasPrefix(path, packageDir+string(filepath.Separator))
		insideReconcile := path == reconcileDir || strings.HasPrefix(path, reconcileDir+string(filepath.Separator))
		insideReconcileCommand := path == reconcileCommandDir || strings.HasPrefix(path, reconcileCommandDir+string(filepath.Separator))
		insideConsumer := path == consumerDir || strings.HasPrefix(path, consumerDir+string(filepath.Separator))
		if !insideCatalog && !insideReconcile && !insideReconcileCommand && !insideConsumer &&
			(bytes.Contains(raw, []byte("nexuscrm-controlplane/catalogapp")) ||
				bytes.Contains(raw, []byte("ConvertLegacyPack"))) {
			t.Errorf("production source outside reconcile/authorized-consumer owners selects Catalog authority: %s", path)
		}
		if insideCatalog && bytes.Contains(raw, []byte(legacyTable)) {
			t.Errorf("production Catalog source reads legacy installed-pack authority: %s", path)
		}
		if insideConsumer {
			for _, forbidden := range [][]byte{
				[]byte("INSERT INTO _System_"),
				[]byte("UPDATE _System_"),
				[]byte("DELETE FROM _System_"),
				[]byte(legacyTable),
				[]byte("official_repo:"),
				[]byte("local_path:"),
				[]byte("os.ReadFile"),
			} {
				if bytes.Contains(raw, forbidden) {
					t.Errorf("authorized Catalog consumer has a write or fallback path %q: %s", forbidden, path)
				}
			}
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}
}

func TestCatalogAppDelegatesOrgWriterMutationsToSharedOwner(t *testing.T) {
	_, file, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("resolve test file")
	}
	packageDir := filepath.Dir(file)
	forbidden := [][]byte{
		[]byte("INSERT INTO _System_CatalogOrgState"),
		[]byte("UPDATE _System_CatalogOrgState"),
	}
	err := filepath.WalkDir(packageDir, func(path string, entry os.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if entry.IsDir() || filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
			return nil
		}
		raw, err := os.ReadFile(path)
		if err != nil {
			return err
		}
		for _, mutation := range forbidden {
			if bytes.Contains(raw, mutation) {
				t.Errorf("Catalog App bypasses the shared org writer in %s through %q", path, mutation)
			}
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}
}

func testRegisteredRelease(t *testing.T) RegisteredRelease {
	return testRegisteredReleaseVersion(t, "1.0.0", "Subject")
}

func testRegisteredReleaseVersion(t *testing.T, version, field string) RegisteredRelease {
	return testRegisteredReleaseVersionForApp(t, "io.example.issues", version, field)
}

func testRegisteredReleaseVersionForApp(t *testing.T, appID, version, field string) RegisteredRelease {
	return testRegisteredReleaseVersionForAppNamespace(t, appID, "io.example.issues", version, field)
}

func testRegisteredReleaseVersionForAppNamespace(
	t *testing.T,
	appID string,
	namespaceID string,
	version string,
	field string,
) RegisteredRelease {
	t.Helper()
	behavior, err := json.Marshal(map[string]any{"fields": []string{field}})
	if err != nil {
		t.Fatal(err)
	}
	contentDigest, err := appauthority.ComponentDigest("metadata.object.v1", 1, behavior)
	if err != nil {
		t.Fatal(err)
	}
	component := appauthority.Component{ComponentKind: "metadata.object.v1", ComponentFormatVersion: 1,
		NamespaceID: namespaceID, BusinessKey: "Issue", DefinitionVersion: "1",
		LocalDependencies: []string{}, ExternalComponentRefs: []appauthority.ExternalComponentRef{},
		OverridePolicy: appauthority.OverridePolicyReplace, RemovalPolicy: appauthority.RemovalPolicyRemoveIfUnreferenced,
		ContentDigest: contentDigest}
	component.ComponentID = appauthority.ComponentID(component.NamespaceID, component.ComponentKind, component.BusinessKey)
	bundle := appauthority.MetadataBundle{SchemaVersion: appauthority.MetadataBundleSchemaVersion, Components: []appauthority.Component{component}}
	manifest := appauthority.AppManifest{SchemaVersion: appauthority.AppManifestSchemaVersion, AppID: appID, PublisherID: "io.example",
		SemanticVersion: version, MetadataBundleDigest: testDigest("placeholder"), Dependencies: []appauthority.Dependency{},
		OwnedNamespaces: []string{namespaceID}, RequiredProtocols: []appauthority.ProtocolRequirement{},
		RequiredEngineCapabilities: []string{"runtime.records.read.v1"}, ProvidedCapabilities: []appauthority.ProvidedCapability{{
			CapabilityID: namespaceID + ".read.v1", Kind: appauthority.CapabilityKindServiceHandler,
			HandlerRef: namespaceID + ".handler.read.v1", RequiredRuntimeCapabilities: []string{"runtime.records.read.v1"},
		}}, FrontendCompatibility: appauthority.FrontendCompatibility{Mode: appauthority.FrontendModeNone}}
	metadataDigest, err := appauthority.MetadataBundleDigest(bundle, manifest)
	if err != nil {
		t.Fatal(err)
	}
	manifest.MetadataBundleDigest = metadataDigest
	verified, err := appauthority.VerifyPackage(appauthority.Package{Manifest: manifest, Bundle: bundle,
		ComponentBlobs: []appauthority.ComponentBlob{{ComponentID: component.ComponentID, CanonicalBehavior: behavior}}})
	if err != nil {
		t.Fatal(err)
	}
	return registeredRelease(verified)
}

func testDigest(value string) string { return digestParts("test", value) }
