package usecase

import (
	"context"
	"testing"

	"haixun-backend/internal/library/clock"
	"haixun-backend/internal/model/job/domain/entity"
	domusecase "haixun-backend/internal/model/job/domain/usecase"
)

func TestRunSchedulerTick_CreatesRun(t *testing.T) {
	ctx := context.Background()
	template := demoTemplate()
	schedules := &memoryScheduleRepo{}
	queue := newMemoryQueueRepo()
	runs := newMemoryRunRepo(nil)
	uc := testUseCaseFull(template, runs, schedules, queue)

	now := clock.NowUnixNano()
	schedule := &entity.Schedule{
		TemplateType: template.Type,
		Scope:        "user",
		ScopeID:      "scheduler-user",
		Enabled:      true,
		Cron:         "0 * * * *",
		Timezone:     "Asia/Taipei",
		NextRunAt:    now - 1,
	}
	_, _ = schedules.Create(ctx, schedule)

	created, err := uc.RunSchedulerTick(ctx, "test-holder")
	if err != nil {
		t.Fatalf("RunSchedulerTick() error = %v", err)
	}
	if created != 1 {
		t.Fatalf("created = %d, want 1", created)
	}
	if len(queue.queued("go")) == 0 {
		t.Fatal("expected queued job from scheduler tick")
	}
	if runs.run == nil {
		t.Fatal("expected run to be created")
	}
	meta, ok := runs.run.Payload[schedulePayloadKey].(map[string]any)
	if !ok {
		t.Fatal("expected _schedule payload metadata")
	}
	if meta["timezone"] != "Asia/Taipei" {
		t.Fatalf("timezone = %v, want Asia/Taipei", meta["timezone"])
	}
	if meta["storage_tz"] != clock.StorageTimezone {
		t.Fatalf("storage_tz = %v, want %s", meta["storage_tz"], clock.StorageTimezone)
	}
	triggeredAt, ok := meta["triggered_at"].(int64)
	if !ok || triggeredAt <= 0 {
		t.Fatalf("triggered_at = %v, want positive unix nano UTC", meta["triggered_at"])
	}
}

func TestCreateSchedule_InvalidCron(t *testing.T) {
	ctx := context.Background()
	template := demoTemplate()
	uc := testUseCaseFull(template, newMemoryRunRepo(nil), &memoryScheduleRepo{}, newMemoryQueueRepo())

	_, err := uc.CreateSchedule(ctx, domusecase.CreateScheduleRequest{
		TemplateType: template.Type,
		Scope:        "user",
		ScopeID:      "u1",
		Cron:         "invalid",
	})
	if err == nil {
		t.Fatal("expected invalid cron error")
	}
}
