package job

import (
	"log/slog"
	"testing"
	"time"

	"code.chimeric.al/chimerical/odidere/internal/config"
)

func TestConfigValidate(t *testing.T) {
	tests := []struct {
		name    string
		config  config.JobConfig
		wantErr bool
	}{
		{
			name:    "empty config",
			config:  config.JobConfig{},
			wantErr: true,
		},
		{
			name: "missing name",
			config: config.JobConfig{
				Schedule: "0 9 * * *",
				Task:     "do something",
			},
			wantErr: true,
		},
		{
			name: "missing task",
			config: config.JobConfig{
				Name:     "test",
				Schedule: "0 9 * * *",
			},
			wantErr: true,
		},
		{
			name: "missing schedule",
			config: config.JobConfig{
				Name: "test",
				Task: "do something",
			},
			wantErr: true,
		},
		{
			name: "negative max iterations",
			config: config.JobConfig{
				Name:          "test",
				Task:          "do something",
				Schedule:      "0 9 * * *",
				MaxIterations: -1,
			},
			wantErr: true,
		},
		{
			name: "minimal valid config",
			config: config.JobConfig{
				Name:     "test",
				Task:     "do something",
				Schedule: "0 9 * * *",
			},
			wantErr: false,
		},
		{
			name: "full valid config",
			config: config.JobConfig{
				Name:          "test",
				Task:          "do something",
				Schedule:      "0 9 * * *",
				Timeout:       "10m",
				MaxIterations: 20,
				SystemMessage: "You are an assistant.",
			},
			wantErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.config.Validate()
			if (err != nil) != tt.wantErr {
				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestConfigMaxIterations(t *testing.T) {
	// Zero means unlimited
	cfg := config.JobConfig{Name: "test"}
	if got := cfg.MaxIterations; got != 0 {
		t.Errorf("default max iterations = %d, want 0", got)
	}

	cfg.MaxIterations = 0
	if got := cfg.MaxIterations; got != 0 {
		t.Errorf("explicit zero max iterations = %d, want 0", got)
	}

	// Positive value passes through
	cfg.MaxIterations = 25
	if got := cfg.MaxIterations; got != 25 {
		t.Errorf("custom max iterations = %d, want 25", got)
	}
}

func TestConfigTimeout(t *testing.T) {
	cfg := config.JobConfig{Name: "test"}
	if cfg.Timeout != "" {
		t.Errorf("default timeout = %q, want empty", cfg.Timeout)
	}

	cfg.Timeout = "10m"
	got, err := time.ParseDuration(cfg.Timeout)
	if err != nil {
		t.Fatalf("ParseDuration(%q) error = %v", cfg.Timeout, err)
	}
	if got.Minutes() != 10 {
		t.Errorf("parsed timeout = %v, want 10m", got)
	}
}

func TestNew(t *testing.T) {
	cfg := config.JobConfig{
		Name:          "test",
		Task:          "do something",
		Schedule:      "0 9 * * *",
		Timeout:       "10m",
		MaxIterations: 20,
		SystemMessage: "You are an assistant.",
	}

	j, err := New(cfg, slog.Default(), nil, "test-model")
	if err != nil {
		t.Fatalf("New() error = %v", err)
	}

	if j.Name() != "test" {
		t.Errorf("Name() = %q, want %q", j.Name(), "test")
	}
	if j.Schedule() != "0 9 * * *" {
		t.Errorf("Schedule() = %q, want %q", j.Schedule(), "0 9 * * *")
	}
	if j.SystemMessage() != "You are an assistant." {
		t.Errorf("SystemMessage() = %q, want %q", j.SystemMessage(), "You are an assistant.")
	}
	if j.Task() != "do something" {
		t.Errorf("Task() = %q, want %q", j.Task(), "do something")
	}
	if j.Timeout().Minutes() != 10 {
		t.Errorf("Timeout() = %v, want 10m", j.Timeout())
	}
	if j.MaxIterations() != 20 {
		t.Errorf("MaxIterations() = %d, want 20", j.MaxIterations())
	}
	if j.Model() != "test-model" {
		t.Errorf("Model() = %q, want %q", j.Model(), "test-model")
	}
	if j.Cron() == nil {
		t.Error("Cron() = nil, want non-nil")
	}
}

func TestNew_InvalidSchedule(t *testing.T) {
	cfg := config.JobConfig{
		Name:     "test",
		Task:     "do something",
		Schedule: "not-a-cron",
	}

	_, err := New(cfg, slog.Default(), nil, "test-model")
	if err == nil {
		t.Fatal("New() expected error for invalid schedule")
	}
}

func TestNew_InvalidTimeout(t *testing.T) {
	cfg := config.JobConfig{
		Name:     "test",
		Task:     "do something",
		Schedule: "0 9 * * *",
		Timeout:  "not-a-duration",
	}

	_, err := New(cfg, slog.Default(), nil, "test-model")
	if err == nil {
		t.Fatal("New() expected error for invalid timeout")
	}
}
