package boundary_test

import (
	"bytes"
	"encoding/json"
	"io"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const releaseInventoryR1APath = "docs/refactor/serviceification/release-artifact-delivery-inventory-r1a.json"

type releaseInventoryR1A struct {
	Schema               string                         `json:"schema"`
	Status               string                         `json:"status"`
	AuditedAt            string                         `json:"audited_at"`
	TrackingIssue        string                         `json:"tracking_issue"`
	Repositories         []releaseInventoryRepository   `json:"repositories"`
	Artifacts            []releaseInventoryArtifact     `json:"artifacts"`
	DeploymentInputs     []releaseInventoryInput        `json:"deployment_inputs"`
	CurrentDeliveryTuple releaseInventoryDeliveryTuple  `json:"current_delivery_tuple"`
	Gaps                 releaseInventoryGapAssignments `json:"gaps"`
}

type releaseInventoryRepository struct {
	Name            string `json:"name"`
	Revision        string `json:"revision"`
	ReleaseIdentity string `json:"release_identity"`
}

type releaseInventoryArtifact struct {
	ID                            string   `json:"id"`
	Class                         string   `json:"class"`
	Owner                         *string  `json:"owner"`
	CurrentAuditedRelease         string   `json:"current_audited_release"`
	CurrentNexusCRMPin            string   `json:"current_nexuscrm_pin"`
	AuthoritativeVersionOrRef     string   `json:"authoritative_version_or_ref"`
	BuildInputCommitOrTag         string   `json:"build_input_commit_or_tag"`
	PublicationDestination        string   `json:"publication_destination"`
	InstallationOrDeploymentInput string   `json:"installation_or_deployment_input"`
	CompatibilityAssumptions      string   `json:"compatibility_assumptions"`
	Publication                   string   `json:"publication"`
	Consumer                      string   `json:"consumer"`
	ImmutableIdentity             bool     `json:"immutable_identity"`
	ChecksumOrProvenance          string   `json:"checksum_or_provenance"`
	Rollback                      string   `json:"rollback"`
	Evidence                      []string `json:"evidence"`
}

type releaseInventoryDeliveryTuple struct {
	DeploymentAuthority      string `json:"deployment_authority"`
	NexusCRMRevision         string `json:"nexuscrm_revision"`
	ContractAndWireVersions  string `json:"contract_and_wire_versions"`
	L0ServiceVersions        string `json:"l0_service_versions"`
	L1AppPackRevision        string `json:"l1_app_pack_revision"`
	L1AppServiceRevision     string `json:"l1_appservice_revision"`
	L2OverlayRevision        string `json:"l2_overlay_revision"`
	FrontendRevision         string `json:"frontend_revision"`
	SchemaMigrationRevision  string `json:"schema_migration_revision"`
	EnvironmentConfiguration string `json:"environment_configuration"`
}

type releaseInventoryInput struct {
	ID            string   `json:"id"`
	Owner         string   `json:"owner"`
	InputNames    []string `json:"input_names"`
	Consumers     []string `json:"consumers"`
	IdentityClass string   `json:"identity_class"`
	Evidence      []string `json:"evidence"`
}

type releaseInventoryGapAssignments struct {
	R1B []string `json:"r1b_release_tuple_decisions"`
	R2  []string `json:"r2_build_publication_work"`
	R3  []string `json:"r3_deployment_integration_work"`
}

func TestReleaseInventoryR1ACoversAllRepositoriesAndOutputs(t *testing.T) {
	manifest := loadReleaseInventoryR1A(t)
	if manifest.Schema != "nexuscrm.serviceification.release-inventory.r1a.v1" {
		t.Fatalf("schema = %q", manifest.Schema)
	}
	if manifest.Status != "descriptive_current_state_not_release_authority" {
		t.Fatalf("status = %q; R1a must not become release authority", manifest.Status)
	}
	if manifest.AuditedAt == "" || manifest.TrackingIssue != "https://github.com/pingcap-inc/NexusCRM/issues/3624" {
		t.Fatalf("audit identity is incomplete: date=%q issue=%q", manifest.AuditedAt, manifest.TrackingIssue)
	}

	wantRepositories := map[string]bool{
		"pingcap-inc/NexusCRM":              false,
		"pingcap-inc/nexuscrm-contract":     false,
		"pingcap-inc/nexuscrm-controlplane": false,
		"pingcap-inc/nexuscrm-api-host":     false,
		"pingcap-inc/nexuscrm-connectors":   false,
		"pingcap-inc/nexuscrm-app-packs":    false,
		"pingcap-inc/nexuscrm-pingcap-pack": false,
	}
	if len(manifest.Repositories) != len(wantRepositories) {
		t.Fatalf("repositories = %d, want exactly the seven release-boundary repositories", len(manifest.Repositories))
	}
	for _, repo := range manifest.Repositories {
		seen, exists := wantRepositories[repo.Name]
		if !exists || seen {
			t.Fatalf("unexpected or duplicate repository %q", repo.Name)
		}
		if !validCommitSHA(repo.Revision) || strings.TrimSpace(repo.ReleaseIdentity) == "" {
			t.Fatalf("repository evidence is incomplete: %#v", repo)
		}
		wantRepositories[repo.Name] = true
	}
	for repo, seen := range wantRepositories {
		if !seen {
			t.Fatalf("missing repository %q", repo)
		}
	}

	requiredArtifacts := map[string]bool{
		"contract-root-go-module":          false,
		"contract-wire-go-module":          false,
		"controlplane-go-module":           false,
		"api-host-go-module":               false,
		"connectors-go-module":             false,
		"nexuscrm-core-module-closure":     false,
		"crm-backend-and-setup-binaries":   false,
		"runtime-api-image":                false,
		"runtime-worker-image":             false,
		"l1-appservice-artifact":           false,
		"frontend-bundle":                  false,
		"l1-metadata-packages":             false,
		"l1-frontend-source":               false,
		"l2-overlay-and-final-pack":        false,
		"release-tuple-verification-input": false,
		"staging-release-tag":              false,
		"production-release-directory":     false,
		"pr-uat-all-in-one-image":          false,
		"schema-and-migration-program":     false,
	}
	for _, artifact := range manifest.Artifacts {
		seen, exists := requiredArtifacts[artifact.ID]
		if !exists || seen {
			t.Fatalf("unexpected or duplicate artifact %q", artifact.ID)
		}
		for label, value := range map[string]string{
			"class":                            artifact.Class,
			"authoritative_version_or_ref":     artifact.AuthoritativeVersionOrRef,
			"build_input_commit_or_tag":        artifact.BuildInputCommitOrTag,
			"publication_destination":          artifact.PublicationDestination,
			"installation_or_deployment_input": artifact.InstallationOrDeploymentInput,
			"compatibility_assumptions":        artifact.CompatibilityAssumptions,
			"publication":                      artifact.Publication,
			"consumer":                         artifact.Consumer,
			"checksum_or_provenance":           artifact.ChecksumOrProvenance,
			"rollback":                         artifact.Rollback,
		} {
			if strings.TrimSpace(value) == "" {
				t.Fatalf("artifact %s has blank %s", artifact.ID, label)
			}
		}
		if artifact.ID == "l1-appservice-artifact" {
			if artifact.Owner != nil || artifact.Publication != "absent" || artifact.Consumer != "none" {
				t.Fatalf("inventory manufactured a current AppService: %#v", artifact)
			}
		} else if artifact.Owner == nil || strings.TrimSpace(*artifact.Owner) == "" {
			t.Fatalf("artifact %s has no current owner", artifact.ID)
		}
		if len(artifact.Evidence) == 0 {
			t.Fatalf("artifact %s has no evidence", artifact.ID)
		}
		for _, evidence := range artifact.Evidence {
			if !strings.Contains(evidence, "@") || !strings.Contains(evidence, ":") {
				t.Fatalf("artifact %s has unpinned evidence %q", artifact.ID, evidence)
			}
		}
		requiredArtifacts[artifact.ID] = true
	}
	for artifact, seen := range requiredArtifacts {
		if !seen {
			t.Fatalf("missing release-shaped output %q", artifact)
		}
	}
}

func TestReleaseInventoryR1AHasCompleteTupleAndAssignedGaps(t *testing.T) {
	manifest := loadReleaseInventoryR1A(t)
	requiredInputs := map[string]bool{
		"release-source-selection":          false,
		"l0-module-build-closure":           false,
		"pack-composition-and-install":      false,
		"frontend-build":                    false,
		"schema-metadata-data-convergence":  false,
		"environment-runtime-configuration": false,
		"deployment-topology-and-cutover":   false,
		"pr-uat-image-and-ecs":              false,
		"independent-runtime-skeleton":      false,
	}
	for _, input := range manifest.DeploymentInputs {
		seen, exists := requiredInputs[input.ID]
		if !exists || seen {
			t.Fatalf("unexpected or duplicate deployment input %q", input.ID)
		}
		if strings.TrimSpace(input.Owner) == "" || strings.TrimSpace(input.IdentityClass) == "" || len(input.InputNames) == 0 || len(input.Consumers) == 0 || len(input.Evidence) == 0 {
			t.Fatalf("deployment input is incomplete: %#v", input)
		}
		for _, evidence := range input.Evidence {
			if !strings.Contains(evidence, "@") || !strings.Contains(evidence, ":") {
				t.Fatalf("deployment input %s has unpinned evidence %q", input.ID, evidence)
			}
		}
		requiredInputs[input.ID] = true
	}
	for input, seen := range requiredInputs {
		if !seen {
			t.Fatalf("missing deployment input class %q", input)
		}
	}

	tuple := manifest.CurrentDeliveryTuple
	for label, value := range map[string]string{
		"deployment_authority":       tuple.DeploymentAuthority,
		"nexuscrm_revision":          tuple.NexusCRMRevision,
		"contract_and_wire_versions": tuple.ContractAndWireVersions,
		"l0_service_versions":        tuple.L0ServiceVersions,
		"l1_app_pack_revision":       tuple.L1AppPackRevision,
		"l1_appservice_revision":     tuple.L1AppServiceRevision,
		"l2_overlay_revision":        tuple.L2OverlayRevision,
		"frontend_revision":          tuple.FrontendRevision,
		"schema_migration_revision":  tuple.SchemaMigrationRevision,
		"environment_configuration":  tuple.EnvironmentConfiguration,
	} {
		if strings.TrimSpace(value) == "" {
			t.Fatalf("current delivery tuple has blank %s", label)
		}
	}
	if tuple.L1AppServiceRevision != "absent" || !strings.Contains(tuple.L0ServiceVersions, "absent") {
		t.Fatalf("tuple must preserve current absent service artifacts: %#v", tuple)
	}
	for owner, gaps := range map[string][]string{"R1b": manifest.Gaps.R1B, "R2": manifest.Gaps.R2, "R3": manifest.Gaps.R3} {
		if len(gaps) == 0 {
			t.Fatalf("%s has no assigned gaps", owner)
		}
		for _, gap := range gaps {
			if strings.TrimSpace(gap) == "" {
				t.Fatalf("%s contains a blank gap", owner)
			}
		}
	}
}

func loadReleaseInventoryR1A(t *testing.T) releaseInventoryR1A {
	t.Helper()
	root := repoRoot(t)
	data, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(releaseInventoryR1APath)))
	if err != nil {
		t.Fatalf("read release inventory: %v", err)
	}
	var manifest releaseInventoryR1A
	decoder := json.NewDecoder(bytes.NewReader(data))
	decoder.DisallowUnknownFields()
	if err := decoder.Decode(&manifest); err != nil {
		t.Fatalf("decode release inventory: %v", err)
	}
	if err := decoder.Decode(&struct{}{}); err != io.EOF {
		t.Fatalf("release inventory has trailing JSON content: %v", err)
	}
	return manifest
}
