package handler

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"codeberg.org/VARASYS/ZDDC/zddc/internal/config"
)

// TestServeProjectListFiltersHiddenAndScaffolding asserts the project list
// excludes both '.'-prefixed entries (the long-standing rule, e.g. .devshell)
// AND '_'-prefixed entries (operator scaffolding like install.zip's
// _template/ that's reachable by direct URL but should not clutter the
// project picker).
func TestServeProjectListFiltersHiddenAndScaffolding(t *testing.T) {
	root := t.TempDir()

	for _, name := range []string{
		"Project-A",
		"Project-B",
		".devshell", // dot-prefixed dir — must be excluded
		"_template", // underscore scaffolding — must be excluded
		"_archive",
	} {
		if err := os.MkdirAll(filepath.Join(root, name), 0o755); err != nil {
			t.Fatalf("mkdir %s: %v", name, err)
		}
	}

	// A loose .zddc that allows everyone, so ACL doesn't interfere with
	// what we're actually testing (the prefix filter).
	if err := os.WriteFile(filepath.Join(root, ".zddc"),
		[]byte("acl:\n  allow: [\"*\"]\n"), 0o644); err != nil {
		t.Fatalf("write .zddc: %v", err)
	}

	cfg := config.Config{Root: root, EmailHeader: "X-Auth-Request-Email"}

	req := httptest.NewRequest(http.MethodGet, "/", nil)
	req = req.WithContext(context.WithValue(req.Context(), EmailKey, "alice@example.com"))
	rec := httptest.NewRecorder()

	ServeProjectList(cfg, rec, req)

	if rec.Code != http.StatusOK {
		t.Fatalf("status = %d, want 200; body = %s", rec.Code, rec.Body.String())
	}

	var got []map[string]string
	if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
		t.Fatalf("invalid JSON: %v\n%s", err, rec.Body.String())
	}

	want := map[string]bool{"Project-A": true, "Project-B": true}
	if len(got) != len(want) {
		t.Fatalf("got %d projects (%+v), want %d (%v)", len(got), got, len(want), want)
	}
	for _, p := range got {
		if !want[p["name"]] {
			t.Errorf("unexpected project in list: %q", p["name"])
		}
	}
}

// TestServeProjectListIncludesTitleFromPerProjectZddc verifies a project's own
// .zddc `title:` field surfaces in the JSON response; projects without it (or
// without any .zddc) come back with an empty/absent title.
func TestServeProjectListIncludesTitleFromPerProjectZddc(t *testing.T) {
	root := t.TempDir()

	for _, name := range []string{"176109", "197072"} {
		if err := os.MkdirAll(filepath.Join(root, name), 0o755); err != nil {
			t.Fatalf("mkdir %s: %v", name, err)
		}
	}

	if err := os.WriteFile(filepath.Join(root, ".zddc"),
		[]byte("acl:\n  allow: [\"*\"]\n"), 0o644); err != nil {
		t.Fatalf("write root .zddc: %v", err)
	}
	if err := os.WriteFile(filepath.Join(root, "176109", ".zddc"),
		[]byte("title: \"Greenfield Substation\"\n"), 0o644); err != nil {
		t.Fatalf("write project .zddc: %v", err)
	}

	cfg := config.Config{Root: root, EmailHeader: "X-Auth-Request-Email"}

	req := httptest.NewRequest(http.MethodGet, "/", nil)
	req = req.WithContext(context.WithValue(req.Context(), EmailKey, "alice@example.com"))
	rec := httptest.NewRecorder()

	ServeProjectList(cfg, rec, req)
	if rec.Code != http.StatusOK {
		t.Fatalf("status = %d, want 200; body = %s", rec.Code, rec.Body.String())
	}

	var got []ProjectInfo
	if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
		t.Fatalf("invalid JSON: %v\n%s", err, rec.Body.String())
	}

	titles := map[string]string{}
	for _, p := range got {
		titles[p.Name] = p.Title
	}
	if titles["176109"] != "Greenfield Substation" {
		t.Errorf("176109 title = %q, want %q", titles["176109"], "Greenfield Substation")
	}
	if titles["197072"] != "" {
		t.Errorf("197072 title = %q, want empty", titles["197072"])
	}
}
