// markdown_test.go contains unit tests for the Markdown formatting functions
// in the markdown package.
package markdown

import (
	"fmt"
	"net/http"
	"testing"

	"github.com/jmrplens/gitlab-mcp-server/v2/internal/testutil"
	"github.com/jmrplens/gitlab-mcp-server/v2/internal/toolutil"
)

// TestRender_Success verifies Render when success.
func TestRender_Success(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/api/v4/markdown" {
			t.Errorf("unexpected path: %s", r.URL.Path)
		}
		if r.Method != http.MethodPost {
			t.Errorf("unexpected method: %s", r.Method)
		}
		testutil.RespondJSON(w, http.StatusOK, `{"html":"<p>Hello <strong>world</strong></p>"}`)
	})
	client := testutil.NewTestClient(t, handler)
	out, err := Render(t.Context(), client, RenderInput{Text: "Hello **world**"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if out.HTML != "<p>Hello <strong>world</strong></p>" {
		t.Errorf("unexpected HTML: %s", out.HTML)
	}
}

// TestRender_WithGFMAndProject verifies Render when with gfm and project.
func TestRender_WithGFMAndProject(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		testutil.RespondJSON(w, http.StatusOK, `{"html":"<p>Rendered with GFM</p>"}`)
	})
	client := testutil.NewTestClient(t, handler)
	out, err := Render(t.Context(), client, RenderInput{
		Text:    "Hello",
		GFM:     true,
		Project: "my-group/my-project",
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if out.HTML != "<p>Rendered with GFM</p>" {
		t.Errorf("unexpected HTML: %s", out.HTML)
	}
}

// TestRender_Error verifies Render when error.
func TestRender_Error(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusForbidden)
	})
	client := testutil.NewTestClient(t, handler)
	_, err := Render(t.Context(), client, RenderInput{Text: "test"})
	if err == nil {
		t.Fatal("expected error, got nil")
	}
}

// TestFormatRenderMarkdown_Empty verifies FormatRenderMarkdown when empty.
func TestFormatRenderMarkdown_Empty(t *testing.T) {
	result := FormatRenderMarkdown(RenderOutput{})
	if result == nil {
		t.Fatal("expected non-nil result")
	}
	text := fmt.Sprintf("%v", result.Content[0])
	if text == "" {
		t.Fatal("expected non-empty text")
	}
}

// TestFormatRenderMarkdown_WithData verifies FormatRenderMarkdown when with data.
func TestFormatRenderMarkdown_WithData(t *testing.T) {
	result := FormatRenderMarkdown(RenderOutput{HTML: "<p>Hello</p>"})
	if result == nil {
		t.Fatal("expected non-nil result")
	}
	text := fmt.Sprintf("%v", result.Content[0])
	if text == "" {
		t.Fatal("expected non-empty text")
	}
}

// TestRender_CancelledContext verifies Render when cancelled context.
func TestRender_CancelledContext(t *testing.T) {
	client := testutil.NewTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		testutil.RespondJSON(w, http.StatusOK, `{"html":"<p>x</p>"}`)
	}))
	ctx := testutil.CancelledCtx(t)
	_, err := Render(ctx, client, RenderInput{Text: "test"})
	if err == nil {
		t.Fatal("expected error for canceled context, got nil")
	}
}

// TestActionSpecs_Metadata verifies canonical metadata for markdown rendering.
func TestActionSpecs_Metadata(t *testing.T) {
	client := testutil.NewTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	specs := ActionSpecs(client)

	if len(specs) != 1 {
		t.Fatalf("len(ActionSpecs) = %d, want 1", len(specs))
	}
	spec := specs[0]
	if spec.OwnerPackage != "markdown" {
		t.Errorf("OwnerPackage = %q, want markdown", spec.OwnerPackage)
	}
	if spec.IndividualTool.Name != "gitlab_render_markdown" {
		t.Errorf("IndividualTool.Name = %q, want gitlab_render_markdown", spec.IndividualTool.Name)
	}
	if !spec.ReadOnly || !spec.Idempotent {
		t.Error("markdown render action should be read-only and idempotent")
	}
}

// TestActionSpecs_CallRoute verifies markdown rendering through the canonical route.
func TestActionSpecs_CallRoute(t *testing.T) {
	client := testutil.NewTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost && r.URL.Path == "/api/v4/markdown" {
			testutil.RespondJSON(w, http.StatusOK, `{"html":"<p>rendered</p>"}`)
			return
		}
		http.NotFound(w, r)
	}))
	byTool := markdownSpecsByTool(t, ActionSpecs(client))

	result, err := byTool["gitlab_render_markdown"].Route.Handler(t.Context(), map[string]any{"text": "Hello **world**"})
	if err != nil {
		t.Fatalf("Route.Handler error: %v", err)
	}
	if result == nil {
		t.Fatal("Route.Handler returned nil")
	}
}

// markdownSpecsByTool supports markdown specs by tool assertions in markdown tests.
func markdownSpecsByTool(t *testing.T, specs []toolutil.ActionSpec) map[string]toolutil.ActionSpec {
	t.Helper()
	byTool := make(map[string]toolutil.ActionSpec, len(specs))
	for _, spec := range specs {
		byTool[spec.IndividualTool.Name] = spec
	}
	return byTool
}
