package benchmarks

import (
	"encoding/json"
	"fmt"
	"testing"
	"time"

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

// BenchmarkTaskJSONMarshal profiles Task serialization to JSON
// Tier 3 C++ candidate: Zero-copy binary serialization
func BenchmarkTaskJSONMarshal(b *testing.B) {
	task := createTestTask()

	b.ResetTimer()
	b.ReportAllocs()

	for b.Loop() {
		_, err := json.Marshal(task)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkTaskJSONUnmarshal profiles Task deserialization from JSON
// Tier 3 C++ candidate: Memory-mapped binary format
func BenchmarkTaskJSONUnmarshal(b *testing.B) {
	task := createTestTask()
	data, err := json.Marshal(task)
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	b.ReportAllocs()

	for b.Loop() {
		var t queue.Task
		err := json.Unmarshal(data, &t)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkTaskJSONRoundTrip profiles full serialize/deserialize cycle
func BenchmarkTaskJSONRoundTrip(b *testing.B) {
	task := createTestTask()

	b.ResetTimer()
	b.ReportAllocs()

	for b.Loop() {
		data, err := json.Marshal(task)
		if err != nil {
			b.Fatal(err)
		}
		var t queue.Task
		err = json.Unmarshal(data, &t)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkPrewarmStateJSONMarshal profiles PrewarmState serialization
// Used in worker prewarm coordination
func BenchmarkPrewarmStateJSONMarshal(b *testing.B) {
	state := queue.PrewarmState{
		WorkerID:   "worker-12345",
		TaskID:     "task-67890",
		SnapshotID: "snap-abc123",
		StartedAt:  time.Now().UTC().Format(time.RFC3339),
		UpdatedAt:  time.Now().UTC().Format(time.RFC3339),
		Phase:      "running",
		EnvImage:   "fetchml/python:3.11",
		DatasetCnt: 3,
		EnvHit:     5,
		EnvMiss:    1,
		EnvBuilt:   2,
		EnvTimeNs:  1500000000,
	}

	b.ResetTimer()
	b.ReportAllocs()

	for b.Loop() {
		_, err := json.Marshal(state)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkPrewarmStateJSONUnmarshal profiles PrewarmState deserialization
func BenchmarkPrewarmStateJSONUnmarshal(b *testing.B) {
	state := queue.PrewarmState{
		WorkerID:   "worker-12345",
		TaskID:     "task-67890",
		SnapshotID: "snap-abc123",
		StartedAt:  time.Now().UTC().Format(time.RFC3339),
		UpdatedAt:  time.Now().UTC().Format(time.RFC3339),
		Phase:      "running",
		EnvImage:   "fetchml/python:3.11",
		DatasetCnt: 3,
		EnvHit:     5,
		EnvMiss:    1,
		EnvBuilt:   2,
		EnvTimeNs:  1500000000,
	}
	data, err := json.Marshal(state)
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	b.ReportAllocs()

	for b.Loop() {
		var s queue.PrewarmState
		err := json.Unmarshal(data, &s)
		if err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkTaskBatchJSONMarshal profiles batch task serialization
// Critical for queue index operations with many tasks
func BenchmarkTaskBatchJSONMarshal(b *testing.B) {
	tasks := make([]queue.Task, 100)
	for i := 0; i < 100; i++ {
		tasks[i] = createTestTaskWithID(i)
	}

	b.ResetTimer()
	b.ReportAllocs()

	for b.Loop() {
		for _, task := range tasks {
			_, err := json.Marshal(task)
			if err != nil {
				b.Fatal(err)
			}
		}
	}
}

// Helper to create a test task
func createTestTask() queue.Task {
	return createTestTaskWithID(0)
}

func createTestTaskWithID(id int) queue.Task {
	now := time.Now()
	return queue.Task{
		ID:        fmt.Sprintf("task-550e8400-e29b-41d4-a716-44665544%03d", id),
		JobName:   "ml-training-job",
		Args:      "--epochs=100 --batch_size=32 --learning_rate=0.001",
		Status:    "queued",
		Priority:  1000,
		CreatedAt: now,
		DatasetSpecs: []queue.DatasetSpec{
			{Name: "training-data", Version: "v1.2.3", Checksum: "sha256:abc123", URI: "s3://bucket/data/train"},
			{Name: "validation-data", Version: "v1.0.0", Checksum: "sha256:def456", URI: "s3://bucket/data/val"},
		},
		Datasets: []string{"dataset1", "dataset2"},
		Metadata: map[string]string{
			"experiment_id": "exp-12345",
			"user_email":    "user@example.com",
			"model_type":    "transformer",
		},
		CPU:        4,
		MemoryGB:   16,
		GPU:        1,
		GPUMemory:  "24GB",
		UserID:     "user-550e8400-e29b-41d4-a716",
		Username:   "ml_researcher",
		CreatedBy:  "admin",
		MaxRetries: 3,
	}
}
