package jobs

import (
	"testing"
	"time"

	"qycw/go-server/internal/domain/commerce"
)

func TestCycleDays(t *testing.T) {
	tests := map[string]int{
		"hourly":        1,
		"monthly":       30,
		"semi_annually": 180,
		"annually":      365,
		"one_time":      3650,
		"":              30,
	}
	for cycle, want := range tests {
		if got := cycleDays(cycle); got != want {
			t.Fatalf("cycleDays(%q) = %d, want %d", cycle, got, want)
		}
	}
}

func TestApplyGenericBlankProvision(t *testing.T) {
	now := time.Date(2026, 7, 9, 12, 0, 0, 0, time.UTC)
	alias := "custom-service"
	instance := commerce.Instance{
		ID:     42,
		Cycle:  "monthly",
		Alias:  &alias,
		Status: "provisioning",
	}
	product := commerce.Product{ID: 7, Name: "Generic"}

	applyGenericBlankProvision(&instance, product, now)

	if instance.Status != "active" {
		t.Fatalf("status = %q, want active", instance.Status)
	}
	if instance.Hostname == nil || *instance.Hostname != alias {
		t.Fatalf("hostname = %v, want %q", instance.Hostname, alias)
	}
	if instance.ExpiresAt == nil || !instance.ExpiresAt.Equal(now.AddDate(0, 0, 30)) {
		t.Fatalf("expires_at = %v, want +30 days", instance.ExpiresAt)
	}
	if len(instance.UpstreamPayload) == 0 {
		t.Fatal("expected upstream payload")
	}
}

func TestSnapshotForInstance(t *testing.T) {
	raw := commerce.JSONRaw(`[{"product_id":1,"name":"A"},{"product_id":2,"name":"B"}]`)
	got := snapshotForInstance(raw, commerce.Instance{ProductID: 2})
	if got["name"] != "B" {
		t.Fatalf("snapshot name = %v, want B", got["name"])
	}
}

func TestApplyPluginProvisionResultKeepsStringUpstreamIDInPayload(t *testing.T) {
	now := time.Date(2026, 7, 9, 12, 0, 0, 0, time.UTC)
	instance := commerce.Instance{ID: 1, Cycle: "monthly", Status: "provisioning"}
	if err := applyPluginProvisionResult(&instance, "mengnai_bt", map[string]any{
		"upstream_id":   "mnbt-user",
		"hostname":      "mnbt-user",
		"message":       "ok",
		"root_password": "generated-secret",
		"payload": map[string]any{
			"mnbt_username": "mnbt-user",
		},
	}, now); err != nil {
		t.Fatal(err)
	}

	if instance.Status != "active" {
		t.Fatalf("status = %q, want active", instance.Status)
	}
	if instance.UpstreamID != nil {
		t.Fatalf("numeric upstream id = %v, want nil for string upstream id", *instance.UpstreamID)
	}
	if len(instance.UpstreamPayload) == 0 {
		t.Fatal("expected upstream payload")
	}
	if instance.RootPassword == nil || *instance.RootPassword == "generated-secret" {
		t.Fatal("expected encrypted plugin password")
	}
}

func TestBuildProvisionSuccessNotification(t *testing.T) {
	notification := buildProvisionSuccessNotification(&commerce.Instance{ID: 9, UserID: 3})
	if notification.UserID != 3 || notification.Category != "instance" || notification.Level != "success" {
		t.Fatalf("unexpected notification: %#v", notification)
	}
	if notification.Link == nil || *notification.Link != "/control/server/9" {
		t.Fatalf("link = %v, want instance link", notification.Link)
	}
}

func TestNewSettlementWorkerDefaults(t *testing.T) {
	worker := NewSettlementWorker(nil, nil, 0, 0)
	if worker.interval <= 0 {
		t.Fatal("expected default interval")
	}
	if worker.batchSize != 100 {
		t.Fatalf("batchSize = %d, want 100", worker.batchSize)
	}
}

func TestNewUpstreamActionWorkerDefaults(t *testing.T) {
	worker := NewUpstreamActionWorker(nil, nil, 0, 0)
	if worker.interval <= 0 {
		t.Fatal("expected default interval")
	}
	if worker.batchSize != 100 {
		t.Fatalf("batchSize = %d, want 100", worker.batchSize)
	}
}

func TestNewInstanceLifecycleWorkerDefaults(t *testing.T) {
	worker := NewInstanceLifecycleWorker(nil, nil, 0, 0)
	if worker.interval <= 0 {
		t.Fatal("expected default interval")
	}
	if worker.batchSize != 50 {
		t.Fatalf("batchSize = %d, want 50", worker.batchSize)
	}
}
