package reproducibility

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

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

// TestManifestEnvironmentCapture verifies that RunManifest.Environment
// is populated on every scan with ConfigHash and DetectionMethod.
func TestManifestEnvironmentCapture(t *testing.T) {
	t.Run("EnvironmentPopulatedInManifest", func(t *testing.T) {
		// Create config
		cfg := &worker.Config{
			ComplianceMode: "standard",
			MaxWorkers:     4,
			GPUVendor:      "nvidia",
			Sandbox: worker.SandboxConfig{
				NetworkMode:    "none",
				SeccompProfile: "default-hardened",
			},
		}

		// Compute expected config hash
		configHash, err := cfg.ComputeResolvedConfigHash()
		if err != nil {
			t.Fatalf("ComputeResolvedConfigHash failed: %v", err)
		}

		// Perform GPU detection to get detection method
		factory := &worker.GPUDetectorFactory{}
		result := factory.CreateDetectorWithInfo(cfg)
		detectionMethod := result.Info.DetectionMethod

		// Create manifest with environment info
		created := time.Now().UTC()
		m := manifest.NewRunManifest("run-env-test", "task-env", "job-env", created)
		m.Environment = &manifest.ExecutionEnvironment{
			ConfigHash:         configHash,
			GPUDetectionMethod: string(detectionMethod),
			GPUCount:           1,
			MaxWorkers:         cfg.MaxWorkers,
			SandboxNetworkMode: cfg.Sandbox.NetworkMode,
			SandboxNoNewPrivs:  cfg.Sandbox.NoNewPrivileges,
			ComplianceMode:     cfg.ComplianceMode,
		}

		// R.1: Environment must be populated
		if m.Environment == nil {
			t.Fatal("Environment is nil")
		}

		// R.1: Environment.ConfigHash must be non-empty
		if m.Environment.ConfigHash == "" {
			t.Error("Environment.ConfigHash is empty")
		}

		// R.1: Environment.DetectionMethod must be non-empty
		if m.Environment.GPUDetectionMethod == "" {
			t.Error("Environment.DetectionMethod is empty")
		}

		// Verify ConfigHash matches expected value
		if m.Environment.ConfigHash != configHash {
			t.Errorf("ConfigHash mismatch: got %q, want %q", m.Environment.ConfigHash, configHash)
		}

		// Verify DetectionMethod matches
		if m.Environment.GPUDetectionMethod != string(detectionMethod) {
			t.Errorf("DetectionMethod mismatch: got %q, want %q", m.Environment.GPUDetectionMethod, detectionMethod)
		}

		// Scan artifacts
		runDir := t.TempDir()
		mustWrite := func(rel string, data []byte) {
			p := filepath.Join(runDir, rel)
			if err := os.MkdirAll(filepath.Dir(p), 0750); err != nil {
				t.Fatalf("mkdir: %v", err)
			}
			if err := os.WriteFile(p, data, 0600); err != nil {
				t.Fatalf("write file: %v", err)
			}
		}
		mustWrite("results/metrics.jsonl", []byte("metrics"))
		mustWrite("checkpoints/best.pt", []byte("checkpoint"))

		caps := &worker.SandboxConfig{
			MaxArtifactFiles:      100,
			MaxArtifactTotalBytes: 1024 * 1024 * 1024,
		}

		arts, err := worker.ScanArtifacts(runDir, false, caps)
		if err != nil {
			t.Fatalf("ScanArtifacts failed: %v", err)
		}

		// Attach artifacts to manifest
		m.Artifacts = arts

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

		loaded, err := manifest.LoadFromDir(dir)
		if err != nil {
			t.Fatalf("LoadFromDir failed: %v", err)
		}

		// Verify environment persisted
		if loaded.Environment == nil {
			t.Fatal("Environment not persisted in manifest")
		}

		if loaded.Environment.ConfigHash != configHash {
			t.Errorf("loaded ConfigHash = %q, want %q", loaded.Environment.ConfigHash, configHash)
		}

		if loaded.Environment.GPUDetectionMethod != string(detectionMethod) {
			t.Errorf("loaded DetectionMethod = %q, want %q", loaded.Environment.GPUDetectionMethod, detectionMethod)
		}
	})

	t.Run("EnvironmentRequiredFields", func(t *testing.T) {
		env := &manifest.ExecutionEnvironment{
			ConfigHash:         "required-hash",
			GPUDetectionMethod: "config",
			MaxWorkers:         4,
			SandboxNetworkMode: "none",
			SandboxNoNewPrivs:  true,
		}
		// Verify required fields
		_ = env.MaxWorkers
		_ = env.SandboxNoNewPrivs

		if env.ConfigHash == "" {
			t.Error("ConfigHash is required")
		}
		if env.GPUDetectionMethod == "" {
			t.Error("DetectionMethod is required")
		}
		if env.SandboxNetworkMode == "" {
			t.Error("SandboxNetworkMode is required")
		}
	})
}
