package handler

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

func TestTemplateNameFromFrontMatter(t *testing.T) {
	cases := []struct {
		name string
		src  string
		want string
	}{
		{"plain", "---\ntemplate: specification\n---\n\n# H\n", "specification"},
		{"quoted", "---\ntemplate: \"letter\"\n---\n", "letter"},
		{"absent", "---\ntitle: X\n---\n", ""},
		{"no-frontmatter", "# Just a heading\n", ""},
		{"traversal-rejected", "---\ntemplate: ../../etc/passwd\n---\n", ""},
		{"slash-rejected", "---\ntemplate: a/b\n---\n", ""},
		{"crlf", "---\r\ntemplate: report\r\n---\r\n", "report"},
		{"dots-terminator", "---\ntemplate: letter\n...\nbody", "letter"},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			if got := templateNameFromFrontMatter([]byte(c.src)); got != c.want {
				t.Errorf("templateNameFromFrontMatter(%q) = %q, want %q", c.src, got, c.want)
			}
		})
	}
}

func TestResolveTemplateSet_DefaultsAndCascade(t *testing.T) {
	root := t.TempDir()
	party := filepath.Join(root, "working", "AcmeCo")
	if err := os.MkdirAll(party, 0o755); err != nil {
		t.Fatal(err)
	}

	// No overrides, no front matter → embedded report, partials present.
	ts := resolveTemplateSet(root, party, []byte("# Hi\n"))
	if ts.Name != "report.html" {
		t.Fatalf("default doctype: got %q, want report.html", ts.Name)
	}
	if ts.Files["_head.html"] == nil {
		t.Errorf("partial _head.html missing from default set")
	}
	embeddedReport := string(ts.Files["report.html"])

	// Front matter selects a doctype.
	if ts := resolveTemplateSet(root, party, []byte("---\ntemplate: letter\n---\n")); ts.Name != "letter.html" {
		t.Errorf("front-matter doctype: got %q, want letter.html", ts.Name)
	}

	// Project-global override at <root>/.zddc.d/templates/report.html.
	projDir := filepath.Join(root, ".zddc.d", "templates")
	if err := os.MkdirAll(projDir, 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(filepath.Join(projDir, "report.html"), []byte("PROJECT-REPORT"), 0o644); err != nil {
		t.Fatal(err)
	}
	ts = resolveTemplateSet(root, party, []byte("# Hi\n"))
	if string(ts.Files["report.html"]) != "PROJECT-REPORT" {
		t.Errorf("project override not applied: %q", ts.Files["report.html"])
	}
	if string(ts.Files["report.html"]) == embeddedReport {
		t.Errorf("override identical to embedded — overlay didn't happen")
	}

	// Party override wins over project-global.
	partyDir := filepath.Join(party, ".zddc.d", "templates")
	if err := os.MkdirAll(partyDir, 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(filepath.Join(partyDir, "report.html"), []byte("PARTY-REPORT"), 0o644); err != nil {
		t.Fatal(err)
	}
	ts = resolveTemplateSet(root, party, []byte("# Hi\n"))
	if string(ts.Files["report.html"]) != "PARTY-REPORT" {
		t.Errorf("party override should win: got %q", ts.Files["report.html"])
	}

	// A brand-new doctype provided only as an override is adopted as primary.
	if err := os.WriteFile(filepath.Join(partyDir, "memo.html"), []byte("MEMO-TEMPLATE"), 0o644); err != nil {
		t.Fatal(err)
	}
	ts = resolveTemplateSet(root, party, []byte("---\ntemplate: memo\n---\n"))
	if ts.Name != "memo.html" || string(ts.Files["memo.html"]) != "MEMO-TEMPLATE" {
		t.Errorf("custom doctype override: name=%q bytes=%q", ts.Name, ts.Files["memo.html"])
	}
	if ts.Files["_head.html"] == nil {
		t.Errorf("partials should still ride along with a custom doctype override")
	}
}
