package webui

import (
	"strings"
	"testing"

	"kjol/vdom"
)

// The pad's value IS the markup it shows — that is the whole reason it draws into an SVG
// rather than a canvas. If the two could differ, the user would sign one thing and the
// caller would store another.
func TestSignaturePadValueIsWhatIsDrawn(t *testing.T) {
	var got string
	pad := NewSignaturePad(SignaturePadOptions{OnChange: func(svg string) { got = svg }})

	pad.strokes.Set([]sigStroke{{{X: 10, Y: 20}, {X: 30, Y: 40}, {X: 50, Y: 20}}})

	value := pad.SVG()
	shown := vdom.RenderHTML(pad.Render(SignaturePadProps{}))

	// Every path in the value is present in the rendered element.
	paths := sigPaths(pad.strokes.Get())
	if paths == "" {
		t.Fatal("no path was generated for a three-point stroke")
	}
	if !strings.Contains(value, paths) {
		t.Error("the emitted SVG does not contain the strokes it was built from")
	}
	if !strings.Contains(shown, `d="M10,20`) {
		t.Errorf("the rendered pad is not showing the stroke:\n%s", shown)
	}
	_ = got
}

// An empty pad is an empty string, not a blank drawing. A caller storing the value must
// be able to ask "did they sign?" without parsing SVG.
func TestSignaturePadEmptyIsEmptyString(t *testing.T) {
	pad := NewSignaturePad(SignaturePadOptions{})
	if !pad.IsEmpty() {
		t.Error("a fresh pad should be empty")
	}
	if pad.SVG() != "" {
		t.Errorf("an empty pad produced %q, want \"\"", pad.SVG())
	}
}

// Clear reports the emptiness to the caller. Without the callback a cleared pad would
// leave the last signature sitting in whatever the caller stored it in.
func TestSignaturePadClearNotifies(t *testing.T) {
	got := "not called"
	pad := NewSignaturePad(SignaturePadOptions{OnChange: func(svg string) { got = svg }})
	pad.strokes.Set([]sigStroke{{{X: 1, Y: 1}, {X: 2, Y: 2}}})

	pad.Clear()

	if got != "" {
		t.Errorf("OnChange got %q on clear, want \"\"", got)
	}
	if !pad.IsEmpty() {
		t.Error("the pad is not empty after Clear")
	}
}

// A single point is a tap, not a mark: it has no length, produces no path, and must not
// count as a signature.
func TestSignaturePadIgnoresSinglePointStrokes(t *testing.T) {
	if got := sigPaths([]sigStroke{{{X: 5, Y: 5}}}); got != "" {
		t.Errorf("a one-point stroke produced a path: %q", got)
	}
}

// Two points are a straight line; three or more are smoothed into curves. Handwriting
// drawn as raw polylines looks like a seismograph.
func TestSignaturePadSmoothsLongStrokes(t *testing.T) {
	line := sigPaths([]sigStroke{{{X: 0, Y: 0}, {X: 10, Y: 10}}})
	if !strings.Contains(line, " L10,10") {
		t.Errorf("a two-point stroke should be a straight line: %q", line)
	}
	if strings.Contains(line, "Q") {
		t.Errorf("a two-point stroke has nothing to smooth: %q", line)
	}

	curve := sigPaths([]sigStroke{{{X: 0, Y: 0}, {X: 10, Y: 10}, {X: 20, Y: 0}}})
	if !strings.Contains(curve, "Q") {
		t.Errorf("a three-point stroke should be smoothed: %q", curve)
	}
}
