package security

import (
	"os"
	"strings"
	"testing"
	"time"

	"github.com/jfraeys/fetch_ml/internal/manifest"
)

// TestManifestFilenameNonce verifies that manifest filenames include a cryptographic nonce
// to prevent information disclosure in multi-tenant environments where predictable
// filenames could be enumerated.
func TestManifestFilenameNonce(t *testing.T) {
	t.Run("FilenameIncludesNonce", func(t *testing.T) {
		// Generate multiple filenames and verify they are unique
		filenames := make(map[string]bool)
		for i := 0; i < 10; i++ {
			filename, err := manifest.GenerateManifestFilename()
			if err != nil {
				t.Fatalf("GenerateManifestFilename failed: %v", err)
			}

			// Verify format: run_manifest_<nonce>.json
			if !strings.HasPrefix(filename, "run_manifest_") {
				t.Errorf("filename %q missing required prefix 'run_manifest_'", filename)
			}
			if !strings.HasSuffix(filename, ".json") {
				t.Errorf("filename %q missing required suffix '.json'", filename)
			}

			// Extract and verify nonce
			nonce := manifest.ParseManifestFilename(filename)
			if nonce == "" {
				t.Errorf("failed to parse nonce from filename %q", filename)
			}
			if len(nonce) != 32 {
				t.Errorf("nonce length = %d, want 32 hex chars", len(nonce))
			}

			// Verify uniqueness (no collisions in 10 generations)
			if filenames[filename] {
				t.Errorf("duplicate filename generated: %q", filename)
			}
			filenames[filename] = true
		}
	})

	t.Run("ManifestWrittenWithNonce", func(t *testing.T) {
		// Generate a nonce for the manifest
		nonce, err := manifest.GenerateManifestNonce()
		if err != nil {
			t.Fatalf("GenerateManifestNonce failed: %v", err)
		}

		// Create a manifest with nonce in Environment
		created := time.Now().UTC()
		m := manifest.NewRunManifest("run-test-nonce", "task-nonce", "job-nonce", created)
		m.CommitID = "deadbeef"
		m.Environment = &manifest.ExecutionEnvironment{
			ConfigHash:    "abc123",
			ManifestNonce: nonce,
		}

		dir := t.TempDir()
		if err := m.WriteToDir(dir); err != nil {
			t.Fatalf("WriteToDir failed: %v", err)
		}

		// List files in directory
		entries, err := os.ReadDir(dir)
		if err != nil {
			t.Fatalf("ReadDir failed: %v", err)
		}

		// Find manifest file
		var manifestFile string
		for _, entry := range entries {
			if strings.HasPrefix(entry.Name(), "run_manifest_") && strings.HasSuffix(entry.Name(), ".json") {
				manifestFile = entry.Name()
				break
			}
		}

		if manifestFile == "" {
			t.Fatal("no manifest file found with expected naming pattern")
		}

		// Verify nonce is present in filename
		parsedNonce := manifest.ParseManifestFilename(manifestFile)
		if parsedNonce == "" {
			t.Errorf("manifest file %q does not contain a valid nonce", manifestFile)
		}
		if parsedNonce != nonce {
			t.Errorf("nonce mismatch: got %q, want %q", parsedNonce, nonce)
		}
		if len(parsedNonce) != 32 {
			t.Errorf("nonce length = %d, want 32 hex chars", len(parsedNonce))
		}

		// Verify file can be loaded back
		loaded, err := manifest.LoadFromDir(dir)
		if err != nil {
			t.Fatalf("LoadFromDir failed: %v", err)
		}
		if loaded.RunID != m.RunID {
			t.Errorf("loaded RunID = %q, want %q", loaded.RunID, m.RunID)
		}
	})

	t.Run("NonceUniqueness", func(t *testing.T) {
		// Generate many nonces to check for collisions (statistical test)
		nonces := make(map[string]int)
		iterations := 100

		for i := 0; i < iterations; i++ {
			nonce, err := manifest.GenerateManifestNonce()
			if err != nil {
				t.Fatalf("GenerateManifestNonce failed: %v", err)
			}
			nonces[nonce]++
		}

		// Check for any collisions
		collisions := 0
		for nonce, count := range nonces {
			if count > 1 {
				t.Errorf("nonce collision detected: %q appeared %d times", nonce, count)
				collisions++
			}
		}

		if collisions > 0 {
			t.Fatalf("detected %d nonce collisions in %d iterations", collisions, iterations)
		}

		t.Logf("Generated %d unique nonces with no collisions", iterations)
	})
}
