package contentdata

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

func writeContent(t *testing.T, name, body string) string {
	t.Helper()
	dir := t.TempDir()
	if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil {
		t.Fatal(err)
	}
	return dir
}

func TestLoadGlossaryOrderAndLookup(t *testing.T) {
	dir := writeContent(t, "glossary.yaml", `
terms:
- slug: b-term
  term: B
  short: short b
  body: |-
    Body <b>b</b> with {base} link.
- slug: a-term
  term: A
  short: short a
  body: body a
`)
	g, err := LoadGlossary(dir)
	if err != nil {
		t.Fatalf("LoadGlossary: %v", err)
	}
	// File order, not alphabetical — the index page renders in this order.
	if len(g.Terms) != 2 || g.Terms[0].Slug != "b-term" || g.Terms[1].Slug != "a-term" {
		t.Errorf("order wrong: %+v", g.Terms)
	}
	e, ok := g.Get("b-term")
	if !ok || e.Term != "B" || e.Body != "Body <b>b</b> with {base} link." {
		t.Errorf("Get(b-term) = %+v, %v", e, ok)
	}
	if _, ok := g.Get("missing"); ok {
		t.Error("Get(missing) should report not-found")
	}
}

func TestLoadGlossaryFailsLoud(t *testing.T) {
	cases := map[string]string{
		"empty terms":    "terms: []\n",
		"missing field":  "terms:\n- slug: x\n  term: X\n  short: s\n", // no body
		"missing slug":   "terms:\n- term: X\n  short: s\n  body: b\n",
		"duplicate slug": "terms:\n- {slug: x, term: X, short: s, body: b}\n- {slug: x, term: Y, short: s, body: b}\n",
		"empty required": "terms:\n- {slug: x, term: X, short: '', body: b}\n", // falsy value fails, like the Python's `not entry.get(f)`
	}
	for name, body := range cases {
		if _, err := LoadGlossary(writeContent(t, "glossary.yaml", body)); err == nil {
			t.Errorf("%s: expected an error", name)
		}
	}
}

func TestLoadPages(t *testing.T) {
	dir := writeContent(t, "pages.yaml", `
pages:
  about:
    title: "About | X"
    description: >-
      Folded
      description.
`)
	p, err := LoadPages(dir)
	if err != nil {
		t.Fatalf("LoadPages: %v", err)
	}
	if p["about"].Title != "About | X" || p["about"].Description != "Folded description." {
		t.Errorf("pages = %+v", p)
	}

	if _, err := LoadPages(writeContent(t, "pages.yaml", "pages: {}\n")); err == nil {
		t.Error("empty pages mapping should fail loud")
	}
	if _, err := LoadPages(writeContent(t, "pages.yaml", "pages:\n  about: {title: T}\n")); err == nil {
		t.Error("missing description should fail loud")
	}
}

// Smoke-check against the real committed content files (frontend/content/),
// when present — the same files the Python loader validated at import.
func TestLoadRealContentFiles(t *testing.T) {
	dir := filepath.Join("..", "..", "..", "content")
	if _, err := os.Stat(filepath.Join(dir, "glossary.yaml")); err != nil {
		t.Skipf("real content dir not available: %v", err)
	}
	g, err := LoadGlossary(dir)
	if err != nil {
		t.Fatalf("LoadGlossary(real): %v", err)
	}
	if len(g.Terms) == 0 {
		t.Error("real glossary should have terms")
	}
	p, err := LoadPages(dir)
	if err != nil {
		t.Fatalf("LoadPages(real): %v", err)
	}
	for _, key := range []string{"about", "privacy", "hub", "glossary_index"} {
		if _, ok := p[key]; !ok {
			t.Errorf("real pages.yaml missing key %q (content.py reads it)", key)
		}
	}
}
