package outputstyle

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

func TestResolveBuiltin(t *testing.T) {
	st, ok := Resolve("explanatory", nil)
	if !ok {
		t.Fatal("explanatory built-in should resolve")
	}
	if !st.Builtin || !st.KeepCoding || strings.TrimSpace(st.Body) == "" {
		t.Errorf("unexpected built-in shape: %+v", st)
	}
	// Case-insensitive.
	if _, ok := Resolve("LEARNING", nil); !ok {
		t.Error("resolve should be case-insensitive")
	}
}

func TestResolveDefaultIsNone(t *testing.T) {
	for _, name := range []string{"", "  ", "default"} {
		if _, ok := Resolve(name, nil); ok {
			t.Errorf("Resolve(%q) should be no-style", name)
		}
	}
}

func TestApply(t *testing.T) {
	append1 := Apply("BASE", OutputStyle{Body: "X", KeepCoding: true})
	if append1 != "BASE\n\nX" {
		t.Errorf("keep-coding append = %q", append1)
	}
	replace := Apply("BASE", OutputStyle{Body: "X", KeepCoding: false})
	if replace != "X" {
		t.Errorf("replace = %q, want X", replace)
	}
	if got := Apply("BASE", OutputStyle{Body: "   "}); got != "BASE" {
		t.Errorf("empty body should leave base untouched, got %q", got)
	}
}

func TestListIncludesBuiltinsSorted(t *testing.T) {
	got := List(nil)
	if len(got) < 3 {
		t.Fatalf("expected at least the 3 built-ins, got %d", len(got))
	}
	for i := 1; i < len(got); i++ {
		if got[i-1].Name > got[i].Name {
			t.Errorf("not sorted by name: %q before %q", got[i-1].Name, got[i].Name)
		}
	}
}

func TestCustomFileOverridesBuiltinAndParses(t *testing.T) {
	dir := t.TempDir()
	// Override the built-in "explanatory" with a custom replace-style file.
	md := "---\ndescription: my persona\nkeep-coding-instructions: false\n---\nYou are a pirate. Answer in pirate speak.\n"
	if err := os.WriteFile(filepath.Join(dir, "explanatory.md"), []byte(md), 0o644); err != nil {
		t.Fatal(err)
	}

	st, ok := Resolve("explanatory", []string{dir})
	if !ok {
		t.Fatal("custom explanatory should resolve")
	}
	if st.Builtin {
		t.Error("custom file should override the built-in (Builtin=false)")
	}
	if st.KeepCoding {
		t.Error("keep-coding-instructions: false should disable KeepCoding")
	}
	if st.Description != "my persona" || !strings.Contains(st.Body, "pirate") {
		t.Errorf("frontmatter/body not parsed: %+v", st)
	}
	if got := Apply("CODING PROMPT", st); got != st.Body {
		t.Errorf("a replace-style should drop the base prompt, got %q", got)
	}
}

func TestParseFileNameFromFilename(t *testing.T) {
	dir := t.TempDir()
	if err := os.WriteFile(filepath.Join(dir, "snappy.md"), []byte("Be snappy."), 0o644); err != nil {
		t.Fatal(err)
	}
	st, ok := Resolve("snappy", []string{dir})
	if !ok || st.Name != "snappy" || !st.KeepCoding { // default keep-coding when unspecified
		t.Errorf("filename-derived style wrong: %+v ok=%v", st, ok)
	}
}
