package app

import (
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
	"testing"

	ui "kjol/webui"
)

// Every icon name this app names must actually resolve.
//
// An unregistered name renders an empty, correctly-sized box. That is the right thing
// at runtime — a missing icon should not collapse the layout — but it means a typo is
// invisible: the icon is simply absent, and nothing says why. Two of them (shapes,
// layer-group, which the kit calls squares and layers) shipped in the sidebar looking
// like blank squares before this test existed.
//
// It scans the SOURCE rather than a hand-kept list, so an icon added to a page tomorrow
// is checked tomorrow, without anyone remembering to add it here.
func TestEveryIconNameResolves(t *testing.T) {
	// ui.Icon("x", …) / ui.IconInline("x", …), and the Icon: "x" field on the props
	// structs (buttons, menu items, docs nav).
	patterns := []*regexp.Regexp{
		regexp.MustCompile(`Icon(?:Inline)?\("([a-z0-9-]+)"`),
		regexp.MustCompile(`\bIcon:\s*"([a-z0-9-]+)"`),
	}

	files, err := filepath.Glob("*.go")
	if err != nil {
		t.Fatal(err)
	}

	used := map[string][]string{} // icon name -> files that ask for it
	for _, f := range files {
		if strings.HasSuffix(f, "_test.go") {
			continue
		}
		src, err := os.ReadFile(f)
		if err != nil {
			t.Fatal(err)
		}
		for _, re := range patterns {
			for _, m := range re.FindAllStringSubmatch(string(src), -1) {
				used[m[1]] = append(used[m[1]], f)
			}
		}
	}

	if len(used) == 0 {
		t.Fatal("scanned the package and found no icon names at all — the patterns have gone stale")
	}

	names := make([]string, 0, len(used))
	for n := range used {
		names = append(names, n)
	}
	sort.Strings(names)

	for _, n := range names {
		if !ui.HasIcon(n) {
			t.Errorf("icon %q is not registered (used in %s) — it will render as an empty box",
				n, strings.Join(dedupe(used[n]), ", "))
		}
	}
	t.Logf("checked %d icon names", len(names))
}

func dedupe(in []string) []string {
	seen := map[string]bool{}
	out := in[:0:0]
	for _, s := range in {
		if !seen[s] {
			seen[s] = true
			out = append(out, s)
		}
	}
	return out
}
