package property

import (
	"testing"

	"github.com/jfraeys/fetch_ml/internal/worker"
	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/gen"
	"github.com/leanovate/gopter/prop"
)

// TestPropertyConfigHashAlwaysPresent verifies that any valid config passing Validate()
// produces a non-empty hash. This is a property-based test using gopter.
func TestPropertyConfigHashAlwaysPresent(t *testing.T) {
	parameters := gopter.DefaultTestParameters()
	parameters.Rng.Seed(12345) // Deterministic seed for reproducibility

	properties := gopter.NewProperties(parameters)

	// Property: valid config always has non-empty hash
	properties.Property("valid config always produces non-empty hash", prop.ForAll(
		func(complianceMode string, maxWorkers, port int, host string) bool {
			// Generate a valid config
			cfg := &worker.Config{
				Host:           host,
				Port:           port,
				MaxWorkers:     maxWorkers,
				ComplianceMode: complianceMode,
				GPUVendor:      "none",
				Sandbox: worker.SandboxConfig{
					NetworkMode:     "none",
					SeccompProfile:  "default-hardened",
					NoNewPrivileges: true,
				},
			}

			// Apply security defaults
			cfg.Sandbox.ApplySecurityDefaults()

			// Skip invalid configs (validation would fail)
			if err := cfg.Validate(); err != nil {
				// Invalid configs are okay for this property - we only care about valid ones
				return true
			}

			// Compute hash
			hash, err := cfg.ComputeResolvedConfigHash()
			if err != nil {
				return false
			}

			// Property: hash must be non-empty for valid configs
			return hash != ""
		},
		// Generators for inputs
		gen.OneConstOf("hipaa", "standard", ""),
		gen.IntRange(1, 100),
		gen.IntRange(1, 65535),
		gen.OneConstOf("localhost", "127.0.0.1", "0.0.0.0"),
	))

	properties.TestingRun(t)
}

// TestPropertyConfigHashDeterministic verifies that the same config always
// produces the same hash (deterministic property).
func TestPropertyConfigHashDeterministic(t *testing.T) {
	parameters := gopter.DefaultTestParameters()
	parameters.Rng.Seed(12345)

	properties := gopter.NewProperties(parameters)

	properties.Property("same config produces same hash", prop.ForAll(
		func(host string, port, maxWorkers int, gpuVendor string) bool {
			// Create two identical configs
			cfg1 := &worker.Config{
				Host:       host,
				Port:       port,
				MaxWorkers: maxWorkers,
				GPUVendor:  gpuVendor,
				Sandbox: worker.SandboxConfig{
					NetworkMode:    "none",
					SeccompProfile: "default-hardened",
				},
			}
			cfg1.Sandbox.ApplySecurityDefaults()

			cfg2 := &worker.Config{
				Host:       host,
				Port:       port,
				MaxWorkers: maxWorkers,
				GPUVendor:  gpuVendor,
				Sandbox: worker.SandboxConfig{
					NetworkMode:    "none",
					SeccompProfile: "default-hardened",
				},
			}
			cfg2.Sandbox.ApplySecurityDefaults()

			// Compute hashes
			hash1, err1 := cfg1.ComputeResolvedConfigHash()
			hash2, err2 := cfg2.ComputeResolvedConfigHash()

			if err1 != nil || err2 != nil {
				return false
			}

			// Property: identical configs must have identical hashes
			return hash1 == hash2
		},
		gen.OneConstOf("localhost", "127.0.0.1"),
		gen.IntRange(22, 8080),
		gen.IntRange(1, 32),
		gen.OneConstOf("nvidia", "amd", "none"),
	))

	properties.TestingRun(t)
}
