package security

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/jfraeys/fetch_ml/internal/crypto"
	"github.com/jfraeys/fetch_ml/internal/worker"
)

// TestConfigIntegrityVerification verifies config file integrity and signature verification.
// This test ensures that config files can be signed and their signatures verified.
func TestConfigIntegrityVerification(t *testing.T) {
	t.Run("ConfigLoadWithoutSignature", func(t *testing.T) {
		// Create a temp config file
		tempDir := t.TempDir()
		configPath := filepath.Join(tempDir, "config.yaml")

		configContent := `
host: localhost
port: 22
max_workers: 4
`
		if err := os.WriteFile(configPath, []byte(configContent), 0600); err != nil {
			t.Fatalf("failed to write config: %v", err)
		}

		// Load config without signature verification (default behavior)
		cfg, err := worker.LoadConfig(configPath)
		if err != nil {
			t.Fatalf("LoadConfig failed: %v", err)
		}

		if cfg.Host != "localhost" {
			t.Errorf("host = %q, want localhost", cfg.Host)
		}
		if cfg.Port != 22 {
			t.Errorf("port = %d, want 22", cfg.Port)
		}
	})

	t.Run("ConfigFileTamperingDetection", func(t *testing.T) {
		// Create a temp config file
		tempDir := t.TempDir()
		configPath := filepath.Join(tempDir, "config.yaml")

		configContent := []byte(`
host: localhost
port: 22
max_workers: 4
`)
		if err := os.WriteFile(configPath, configContent, 0600); err != nil {
			t.Fatalf("failed to write config: %v", err)
		}

		// Generate signing keys
		publicKey, privateKey, err := crypto.GenerateSigningKeys()
		if err != nil {
			t.Fatalf("GenerateSigningKeys failed: %v", err)
		}

		// Create signer
		signer, err := crypto.NewManifestSigner(privateKey, "test-key-1")
		if err != nil {
			t.Fatalf("NewManifestSigner failed: %v", err)
		}

		// Sign the config content
		result, err := signer.SignManifestBytes(configContent)
		if err != nil {
			t.Fatalf("SignManifestBytes failed: %v", err)
		}

		// Verify signature against original content
		valid, err := crypto.VerifyManifestBytes(configContent, result, publicKey)
		if err != nil {
			t.Fatalf("VerifyManifestBytes failed: %v", err)
		}
		if !valid {
			t.Error("signature should be valid for original content")
		}

		// Tamper with the config file
		tamperedContent := []byte(`
host: malicious-host
port: 22
max_workers: 4
`)
		if err := os.WriteFile(configPath, tamperedContent, 0600); err != nil {
			t.Fatalf("failed to write tampered config: %v", err)
		}

		// Verify signature against tampered content (should fail)
		valid, err = crypto.VerifyManifestBytes(tamperedContent, result, publicKey)
		if err != nil {
			// Expected - signature doesn't match
			t.Logf("Expected verification error for tampered content: %v", err)
		}
		if valid {
			t.Error("signature should be invalid for tampered content")
		}
	})

	t.Run("MissingSignatureFile", func(t *testing.T) {
		tempDir := t.TempDir()
		configPath := filepath.Join(tempDir, "config.yaml")

		configContent := `
host: localhost
port: 22
`
		if err := os.WriteFile(configPath, []byte(configContent), 0600); err != nil {
			t.Fatalf("failed to write config: %v", err)
		}

		// Config loads without signature
		cfg, err := worker.LoadConfig(configPath)
		if err != nil {
			t.Fatalf("LoadConfig should work without signature: %v", err)
		}

		if cfg == nil {
			t.Error("expected config to be loaded")
		}
	})
}

// TestConfigHashStability verifies that the same config produces the same hash
func TestConfigHashStability(t *testing.T) {
	cfg := &worker.Config{
		Host:       "localhost",
		Port:       22,
		MaxWorkers: 4,
		GPUVendor:  "nvidia",
		Sandbox: worker.SandboxConfig{
			NetworkMode:    "none",
			SeccompProfile: "default-hardened",
		},
	}

	hash1, err := cfg.ComputeResolvedConfigHash()
	if err != nil {
		t.Fatalf("ComputeResolvedConfigHash failed: %v", err)
	}

	hash2, err := cfg.ComputeResolvedConfigHash()
	if err != nil {
		t.Fatalf("ComputeResolvedConfigHash failed: %v", err)
	}

	if hash1 != hash2 {
		t.Error("same config should produce identical hashes")
	}

	// Modify config and verify hash changes
	cfg.MaxWorkers = 8
	hash3, err := cfg.ComputeResolvedConfigHash()
	if err != nil {
		t.Fatalf("ComputeResolvedConfigHash failed: %v", err)
	}

	if hash1 == hash3 {
		t.Error("different configs should produce different hashes")
	}
}
