package web

import (
	"bytes"
	"html/template"
	"strings"
	"testing"

	"gitea.dooplex.hu/admin/felhom-controller/internal/config"
	"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
)

// TestRouteUnpublished asserts F5: routeUnpublished is true exactly for the states where Traefik
// withholds the public route (unhealthy / restarting) and false otherwise.
func TestRouteUnpublished(t *testing.T) {
	cases := []struct {
		state stacks.ContainerState
		want  bool
	}{
		{stacks.StateUnhealthy, true},
		{stacks.StateRestarting, true},
		{stacks.StateRunning, false},
		{stacks.StateStarting, false},
		{stacks.StateDeploying, false},
		{stacks.StateStopped, false},
		{stacks.StateExited, false},
		{stacks.StateNotDeployed, false},
		{stacks.StatePaused, false},
	}
	for _, c := range cases {
		if got := routeUnpublished(c.state); got != c.want {
			t.Errorf("routeUnpublished(%q) = %v, want %v", c.state, got, c.want)
		}
	}
}

// TestTemplatesParseWithFuncmap asserts the real embedded templates (including the stacks.html /
// dashboard.html edits that reference routeUnpublished) parse with the production funcmap. Catches an
// unregistered func or a template syntax error introduced by the F5 edits.
func TestTemplatesParseWithFuncmap(t *testing.T) {
	s := &Server{cfg: &config.Config{}}
	if _, err := template.New("").Funcs(s.templateFuncMap()).ParseFS(templateFS, "templates/*.html"); err != nil {
		t.Fatalf("templates failed to parse with funcmap: %v", err)
	}
}

// TestRouteUnpublishedIndicatorRenders asserts the dashboard/stacks card guard renders the distinct
// indicator for a DEPLOYED + unhealthy stack, and NOT for a healthy one — the exact condition both
// edited templates use ({{if and .Deployed (routeUnpublished .State)}}).
func TestRouteUnpublishedIndicatorRenders(t *testing.T) {
	s := &Server{cfg: &config.Config{}}
	const frag = `{{if and .Deployed (routeUnpublished .State)}}URL-NOT-PUBLISHED{{end}}`
	tmpl, err := template.New("frag").Funcs(s.templateFuncMap()).Parse(frag)
	if err != nil {
		t.Fatal(err)
	}
	type row struct {
		Deployed bool
		State    stacks.ContainerState
	}
	render := func(r row) string {
		var b bytes.Buffer
		if err := tmpl.Execute(&b, r); err != nil {
			t.Fatal(err)
		}
		return b.String()
	}

	if got := render(row{Deployed: true, State: stacks.StateUnhealthy}); !strings.Contains(got, "URL-NOT-PUBLISHED") {
		t.Errorf("deployed+unhealthy should show the indicator, got %q", got)
	}
	if got := render(row{Deployed: true, State: stacks.StateRunning}); strings.Contains(got, "URL-NOT-PUBLISHED") {
		t.Errorf("deployed+running must NOT show the indicator, got %q", got)
	}
	if got := render(row{Deployed: false, State: stacks.StateUnhealthy}); strings.Contains(got, "URL-NOT-PUBLISHED") {
		t.Errorf("not-deployed must NOT show the indicator, got %q", got)
	}
}
