package main

import (
	"testing"

	"git.d-ma.be/mathias/tapir/internal/config"
)

// TestBuildProcessorNilOnIncompleteConfig asserts the queue-only fallback: when a
// required input is missing, buildProcessor returns (nil, nil) — never an error —
// so the web UI degrades to queue-only instead of failing to start.
func TestBuildProcessorNilOnIncompleteConfig(t *testing.T) {
	// A complete config (the fields buildProcessor gates on). The store is nil:
	// buildProcessor must not touch it on the incomplete paths, and the complete
	// path only stores the pointer (no connection), so nil is fine for this test.
	complete := config.Config{
		GatewayURL:     "http://gw/v1",
		YTClientID:     "id",
		YTClientSecret: "secret",
		SecretsFile:    "/tmp/secrets.json",
	}

	tests := []struct {
		name    string
		mutate  func(config.Config) config.Config
		wantNil bool
	}{
		{"complete", func(c config.Config) config.Config { return c }, false},
		{"no gateway url", func(c config.Config) config.Config { c.GatewayURL = ""; return c }, true},
		{"no yt client id", func(c config.Config) config.Config { c.YTClientID = ""; return c }, true},
		{"no yt client secret", func(c config.Config) config.Config { c.YTClientSecret = ""; return c }, true},
		{"no secrets file", func(c config.Config) config.Config { c.SecretsFile = ""; return c }, true},
		{"empty config", func(config.Config) config.Config { return config.Config{} }, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			engine, err := buildProcessor(tt.mutate(complete), nil)
			if err != nil {
				t.Fatalf("buildProcessor returned an error, want nil: %v", err)
			}
			if (engine == nil) != tt.wantNil {
				t.Fatalf("engine == nil is %v, want %v", engine == nil, tt.wantNil)
			}
		})
	}
}

// TestBurstChainModelsLeadsWithOnboardModel: the onboarding burst chain (ADR-028)
// leads with the stronger onboard model, then falls back through the standard
// ADR-022 chain (primary -> local fallback -> cloud), deduped.
func TestBurstChainModelsLeadsWithOnboardModel(t *testing.T) {
	got := burstChainModels(config.Config{
		OnboardSummarizerModel: "iguana/gemma4-26b",
		SummarizerModel:        "koala/phi4-mini",
		FallbackModel:          "iguana/gemma4-26b", // also the onboard model -> dedup
		CloudFallbackModel:     "berget/mistral-small",
	})
	want := []string{"iguana/gemma4-26b", "koala/phi4-mini", "berget/mistral-small"}
	if len(got) != len(want) {
		t.Fatalf("burstChainModels = %v, want %v", got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("burstChainModels = %v, want %v", got, want)
		}
	}
}

// TestBurstChainModelsCloudAbsentWhenDisabled: the NDA lever holds for the burst
// too — empty cloud fallback keeps the burst chain fully local.
func TestBurstChainModelsCloudAbsentWhenDisabled(t *testing.T) {
	got := burstChainModels(config.Config{
		OnboardSummarizerModel: "iguana/gemma4-26b",
		SummarizerModel:        "koala/phi4-mini",
		CloudFallbackModel:     "",
	})
	for _, m := range got {
		if m == "" || m == "berget/mistral-small" {
			t.Fatalf("cloud model leaked into burst chain: %v", got)
		}
	}
}

// TestBuildBurstProcessorNilWhenCollapsed: an empty or primary-equal onboard model
// collapses the burst onto the shared processor (buildBurstProcessor returns nil).
func TestBuildBurstProcessorNilWhenCollapsed(t *testing.T) {
	base := config.Config{
		GatewayURL:      "http://gw/v1",
		YTClientID:      "id",
		YTClientSecret:  "secret",
		SecretsFile:     "/tmp/secrets.json",
		SummarizerModel: "koala/phi4-mini",
	}
	t.Run("empty onboard model", func(t *testing.T) {
		base.OnboardSummarizerModel = ""
		eng, err := buildBurstProcessor(base, nil)
		if err != nil || eng != nil {
			t.Fatalf("buildBurstProcessor = (%v, %v), want (nil, nil)", eng, err)
		}
	})
	t.Run("onboard model equals primary", func(t *testing.T) {
		base.OnboardSummarizerModel = "koala/phi4-mini"
		eng, err := buildBurstProcessor(base, nil)
		if err != nil || eng != nil {
			t.Fatalf("buildBurstProcessor = (%v, %v), want (nil, nil)", eng, err)
		}
	})
}
