package packs

import (
	"strings"
	"testing"
)

func TestFreezeSourceBackedExecutionAtomIdentityRejectsUnmintedAtoms(t *testing.T) {
	for name, atom := range map[string]*SourceBackedExecutionAtom{
		"nil":                     nil,
		"zero":                    {},
		"forged minted flag only": {minted: true},
	} {
		t.Run(name, func(t *testing.T) {
			identity, err := FreezeSourceBackedExecutionAtomIdentity(atom)
			if err == nil || !strings.Contains(err.Error(), "not minted") {
				t.Fatalf("error = %v, want unminted rejection", err)
			}
			if identity != nil {
				t.Fatalf("identity = %#v, want a real nil pointer", identity)
			}
		})
	}
}

func TestSourceBackedExecutionAtomIdentityRejectsUnmintedValues(t *testing.T) {
	target := executionAtomTestPack(t)
	atom, err := FreezeSourceBackedExecutionAtom(target)
	if err != nil {
		t.Fatalf("freeze atom: %v", err)
	}
	for name, identity := range map[string]*SourceBackedExecutionAtomIdentity{
		"nil":                     nil,
		"zero":                    {},
		"forged minted flag only": {minted: true},
		"forged atom only":        {atom: atom, minted: true},
	} {
		t.Run(name, func(t *testing.T) {
			if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, target); err == nil {
				t.Fatal("ValidateSourceBackedExecutionAtomIdentityTarget error = nil, want unminted rejection")
			}
		})
	}
}

func TestValidateSourceBackedExecutionAtomIdentityTargetRequiresExactAtomConstruction(t *testing.T) {
	target := executionAtomTestPack(t)
	dependencyReads := 0
	target.components = []PackComponent{&executionAtomTestComponent{dependencyReads: &dependencyReads}}
	atom, err := FreezeSourceBackedExecutionAtom(target)
	if err != nil {
		t.Fatalf("freeze atom: %v", err)
	}
	if dependencyReads != 2 {
		t.Fatalf("dependency reads after atom freeze = %d, want 2", dependencyReads)
	}
	identity, err := FreezeSourceBackedExecutionAtomIdentity(atom)
	if err != nil {
		t.Fatalf("freeze identity: %v", err)
	}
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, target); err != nil {
		t.Fatalf("validate exact atom and target: %v", err)
	}
	if dependencyReads != 2 {
		t.Fatalf("dependency reads after identity operations = %d, want no plan rebuild", dependencyReads)
	}
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, nil); err == nil || !strings.Contains(err.Error(), "target is nil") {
		t.Fatalf("nil target error = %v, want nil-target rejection", err)
	}

	replacement, err := FreezeSourceBackedExecutionAtom(target)
	if err != nil {
		t.Fatalf("freeze replacement atom: %v", err)
	}
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, replacement, target); err == nil || !strings.Contains(err.Error(), "different atom") {
		t.Fatalf("replacement atom error = %v, want exact-pointer rejection", err)
	}

	original := *atom
	*atom = *replacement
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, target); err == nil || !strings.Contains(err.Error(), "different atom") {
		t.Fatalf("in-place replacement error = %v, want atom-construction rejection", err)
	}
	*atom = SourceBackedExecutionAtom{}
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, target); err == nil {
		t.Fatal("in-place zeroing error = nil, want atom-construction rejection")
	}
	*atom = original
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, target); err != nil {
		t.Fatalf("validate restored exact atom: %v", err)
	}

	substitute := executionAtomTestPack(t)
	if err := ValidateSourceBackedExecutionAtomIdentityTarget(identity, atom, substitute); err == nil || !strings.Contains(err.Error(), "different target") {
		t.Fatalf("substitute target error = %v, want exact-target rejection", err)
	}
}
