package recipes

import (
	"os"
	"path/filepath"
	"testing"
)

func TestBuiltinRecipes(t *testing.T) {
	// Ensure all expected built-in recipes exist
	expected := []string{"cursor", "windsurf", "cody", "kilocode", "claude", "gemini", "factory", "aider"}

	for _, name := range expected {
		recipe, ok := BuiltinRecipes[name]
		if !ok {
			t.Errorf("missing built-in recipe: %s", name)
			continue
		}
		if recipe.Name == "" {
			t.Errorf("recipe %s has empty Name", name)
		}
		if recipe.Type == "" {
			t.Errorf("recipe %s has empty Type", name)
		}
	}
}

func TestGetRecipe(t *testing.T) {
	// Test getting a built-in recipe
	recipe, err := GetRecipe("cursor", "")
	if err != nil {
		t.Fatalf("GetRecipe(cursor): %v", err)
	}
	if recipe.Name != "Cursor IDE" {
		t.Errorf("got Name=%q, want 'Cursor IDE'", recipe.Name)
	}
	if recipe.Path != ".cursor/rules/beads.mdc" {
		t.Errorf("got Path=%q, want '.cursor/rules/beads.mdc'", recipe.Path)
	}

	// Test unknown recipe
	_, err = GetRecipe("nonexistent", "")
	if err == nil {
		t.Error("GetRecipe(nonexistent) should return error")
	}
}

func TestIsBuiltin(t *testing.T) {
	if !IsBuiltin("cursor") {
		t.Error("cursor should be builtin")
	}
	if IsBuiltin("myeditor") {
		t.Error("myeditor should not be builtin")
	}
}

func TestListRecipeNames(t *testing.T) {
	names, err := ListRecipeNames("")
	if err != nil {
		t.Fatalf("ListRecipeNames: %v", err)
	}

	// Check that it's sorted
	for i := 1; i < len(names); i++ {
		if names[i-1] > names[i] {
			t.Errorf("names not sorted: %v", names)
			break
		}
	}

	// Check expected recipes present
	found := make(map[string]bool)
	for _, name := range names {
		found[name] = true
	}
	for _, expected := range []string{"cursor", "claude", "aider"} {
		if !found[expected] {
			t.Errorf("expected recipe %s not in list", expected)
		}
	}
}

func TestUserRecipes(t *testing.T) {
	// Create temp directory
	tmpDir, err := os.MkdirTemp("", "recipes-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	// Save a user recipe
	if err := SaveUserRecipe(tmpDir, "myeditor", ".myeditor/rules.md"); err != nil {
		t.Fatalf("SaveUserRecipe: %v", err)
	}

	// Verify file was created
	recipesPath := filepath.Join(tmpDir, "recipes.toml")
	if _, err := os.Stat(recipesPath); os.IsNotExist(err) {
		t.Error("recipes.toml was not created")
	}

	// Load user recipes
	userRecipes, err := LoadUserRecipes(tmpDir)
	if err != nil {
		t.Fatalf("LoadUserRecipes: %v", err)
	}

	recipe, ok := userRecipes["myeditor"]
	if !ok {
		t.Fatal("myeditor recipe not found")
	}
	if recipe.Path != ".myeditor/rules.md" {
		t.Errorf("got Path=%q, want '.myeditor/rules.md'", recipe.Path)
	}
	if recipe.Type != TypeFile {
		t.Errorf("got Type=%q, want 'file'", recipe.Type)
	}

	// GetRecipe should find user recipe
	r, err := GetRecipe("myeditor", tmpDir)
	if err != nil {
		t.Fatalf("GetRecipe(myeditor): %v", err)
	}
	if r.Path != ".myeditor/rules.md" {
		t.Errorf("got Path=%q, want '.myeditor/rules.md'", r.Path)
	}
}

func TestUserRecipeOverride(t *testing.T) {
	// Create temp directory
	tmpDir, err := os.MkdirTemp("", "recipes-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	// Save a user recipe that overrides cursor
	if err := SaveUserRecipe(tmpDir, "cursor", ".my-cursor/rules.md"); err != nil {
		t.Fatalf("SaveUserRecipe: %v", err)
	}

	// GetRecipe should return user's version
	r, err := GetRecipe("cursor", tmpDir)
	if err != nil {
		t.Fatalf("GetRecipe(cursor): %v", err)
	}
	if r.Path != ".my-cursor/rules.md" {
		t.Errorf("user override failed: got Path=%q, want '.my-cursor/rules.md'", r.Path)
	}
}

func TestLoadUserRecipesNoFile(t *testing.T) {
	// Should return nil, nil when no file exists
	recipes, err := LoadUserRecipes("/nonexistent/path")
	if err != nil {
		t.Errorf("LoadUserRecipes should not error on missing file: %v", err)
	}
	if recipes != nil {
		t.Error("LoadUserRecipes should return nil for missing file")
	}
}

func TestTemplate(t *testing.T) {
	// Basic sanity check that template is not empty
	if len(Template) < 100 {
		t.Error("Template is suspiciously short")
	}
	// Check for key content
	if !containsAll(Template, "Beads", "bd ready", "bd create", "bd close") {
		t.Error("Template missing expected content")
	}
}

func containsAll(s string, substrs ...string) bool {
	for _, sub := range substrs {
		found := false
		for i := 0; i <= len(s)-len(sub); i++ {
			if s[i:i+len(sub)] == sub {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}
	return true
}
