package main

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

// TestDiscoverActionSpecGroupBuilders_SortsBuilders verifies DiscoverActionSpecGroupBuilders sorts builders.
func TestDiscoverActionSpecGroupBuilders_SortsBuilders(t *testing.T) {
	sourceDir := t.TempDir()
	writeTestFile(t, filepath.Join(sourceDir, "action_specs.go"), `package tools

func buildWikiActionSpecs() {}
func helper() {}
func buildAccessActionSpecs() {}
`)

	builders, err := discoverActionSpecGroupBuilders(sourceDir)
	if err != nil {
		t.Fatalf("discoverActionSpecGroupBuilders() error = %v", err)
	}
	want := []string{"buildAccessActionSpecs", "buildWikiActionSpecs"}
	if strings.Join(builders, ",") != strings.Join(want, ",") {
		t.Fatalf("builders = %#v, want %#v", builders, want)
	}
}

// TestGenerateManifest_IsDeterministic verifies GenerateManifest is deterministic.
func TestGenerateManifest_IsDeterministic(t *testing.T) {
	builders := []string{"buildAccessActionSpecs", "buildWikiActionSpecs"}
	first, err := generateManifest(builders)
	if err != nil {
		t.Fatalf("generateManifest() error = %v", err)
	}
	second, err := generateManifest(builders)
	if err != nil {
		t.Fatalf("generateManifest() second error = %v", err)
	}
	if !bytes.Equal(first, second) {
		t.Fatalf("generateManifest() was not deterministic")
	}
	for _, want := range []string{
		"// Code generated by cmd/gen_action_catalog_manifest; DO NOT EDIT.",
		"func actionSpecGroupBuilders() []actionSpecGroupBuilder",
		"buildAccessActionSpecs,",
		"buildWikiActionSpecs,",
	} {
		if !bytes.Contains(first, []byte(want)) {
			t.Fatalf("generated manifest missing %q:\n%s", want, first)
		}
	}
}

// TestCheckManifest_DetectsStaleOutput verifies CheckManifest detects stale output.
func TestCheckManifest_DetectsStaleOutput(t *testing.T) {
	path := filepath.Join(t.TempDir(), "action_specs_manifest_gen.go")
	writeTestFile(t, path, "old")
	if err := checkManifest(path, []byte("new")); err == nil {
		t.Fatal("checkManifest() error = nil, want stale manifest error")
	}
}

// writeTestFile writes test file fixture data for tests.
func writeTestFile(t *testing.T, path, content string) {
	t.Helper()
	if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
		t.Fatalf("WriteFile(%s) error = %v", path, err)
	}
}
