package httpserver

import (
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/tim/cairnquire/apps/server/internal/config"
	"github.com/tim/cairnquire/apps/server/internal/docs"
)

func TestBuildBrowserUsesFolderIndex(t *testing.T) {
	browser := buildBrowser([]docs.DocumentRecord{
		{
			Path:      "guide/index.md",
			Title:     "Guide",
			UpdatedAt: time.Now(),
		},
		{
			Path:      "guide/setup.md",
			Title:     "Setup",
			UpdatedAt: time.Now(),
		},
	}, "guide/index.md")

	if len(browser.Columns) != 2 {
		t.Fatalf("len(browser.Columns) = %d, want 2", len(browser.Columns))
	}

	root := browser.Columns[0].Items
	if len(root) != 1 {
		t.Fatalf("len(root items) = %d, want 1", len(root))
	}
	if !root[0].IsFolder || root[0].Name != "Guide" || root[0].URL != "/docs/guide" {
		t.Fatalf("root folder = %#v, want Guide folder linking to /docs/guide", root[0])
	}

	child := browser.Columns[1].Items
	if len(child) != 1 {
		t.Fatalf("len(child items) = %d, want 1", len(child))
	}
	if child[0].Path == "guide/index.md" {
		t.Fatalf("folder index file should be represented by the folder, not repeated as a child file")
	}
}

func TestTrimEditSuffix(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		wantPath string
		wantOK   bool
	}{
		{name: "nested path", input: "guide/setup/edit", wantPath: "guide/setup", wantOK: true},
		{name: "root edit sentinel", input: "edit", wantPath: "", wantOK: true},
		{name: "document route", input: "guide/setup", wantPath: "", wantOK: false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotPath, gotOK := trimEditSuffix(tt.input)
			if gotPath != tt.wantPath || gotOK != tt.wantOK {
				t.Fatalf("trimEditSuffix(%q) = (%q, %t), want (%q, %t)", tt.input, gotPath, gotOK, tt.wantPath, tt.wantOK)
			}
		})
	}
}

func TestIsContentAssetPath(t *testing.T) {
	tests := []struct {
		path string
		want bool
	}{
		{path: "logo.webp", want: true},
		{path: "guide/logo.png", want: true},
		{path: "guide/page", want: false},
		{path: "guide/page.md", want: false},
		{path: "guide/page/edit", want: false},
	}

	for _, tt := range tests {
		t.Run(tt.path, func(t *testing.T) {
			if got := isContentAssetPath(tt.path); got != tt.want {
				t.Fatalf("isContentAssetPath(%q) = %t, want %t", tt.path, got, tt.want)
			}
		})
	}
}

func TestHandleContentAssetServesImageFromSourceDir(t *testing.T) {
	root := t.TempDir()
	image := []byte{
		0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
		0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4,
		0x89,
	}
	if err := os.WriteFile(filepath.Join(root, "logo.png"), image, 0o644); err != nil {
		t.Fatalf("write fixture: %v", err)
	}

	server := &Server{
		config: config.Config{
			Content: config.ContentConfig{SourceDir: root},
		},
	}
	request := httptest.NewRequest(http.MethodGet, "/docs/logo.png", nil)
	recorder := httptest.NewRecorder()

	server.handleContentAsset(recorder, request, "logo.png")

	response := recorder.Result()
	if response.StatusCode != http.StatusOK {
		t.Fatalf("status = %d, want %d", response.StatusCode, http.StatusOK)
	}
	if got := response.Header.Get("Content-Type"); got != "image/png" {
		t.Fatalf("content-type = %q, want image/png", got)
	}
}
