package main

import (
	"net/url"
	"strings"
	"testing"
)

// decodeURIComponent is what static/app.js calls on X-Reply-Text. PathUnescape
// is its Go equivalent for this purpose: both turn %XX into bytes and both
// leave a literal "+" alone. That last part is the whole defect — QueryEscape
// wrote spaces as "+" and the client had no way to tell those from a plus the
// speaker actually said.
func decodeURIComponent(t *testing.T, s string) string {
	t.Helper()
	out, err := url.PathUnescape(s)
	if err != nil {
		t.Fatalf("decodeURIComponent(%q): %v", s, err)
	}
	return out
}

// The reply the QA session actually saw was "на+04.08.2026+ничего+нет."
// (Vikunja #533). Round-tripping through the client's decoder is the assertion
// that matters — checking the encoder in isolation would have passed with
// QueryEscape too.
func TestReplyTextSurvivesTheClientDecoder(t *testing.T) {
	cases := []string{
		"на 04.08.2026 ничего нет.",
		"Я поставила тебе напоминание позвонить маме через час.",
		// A literal plus must stay a plus, which is the case that makes
		// "just replace + with space on the JS side" the wrong fix.
		"два плюс два = 2+2",
		// Headers cannot carry a raw newline. PathEscape writes %0A.
		"первая строка\nвторая строка",
		"", // no reply text at all
	}
	for _, want := range cases {
		encoded := url.PathEscape(want)
		if strings.ContainsAny(encoded, "\r\n") {
			t.Errorf("encoded %q contains a raw newline, which is not a legal header value", want)
		}
		if got := decodeURIComponent(t, encoded); got != want {
			t.Errorf("round trip: got %q, want %q", got, want)
		}
	}
}

// The specific regression, named. QueryEscape is form encoding and this header
// is not a form.
func TestReplyTextDoesNotUseFormEncoding(t *testing.T) {
	const spoken = "на 04.08.2026 ничего нет."
	if got := decodeURIComponent(t, url.QueryEscape(spoken)); got == spoken {
		t.Skip("QueryEscape round-trips here, so this test proves nothing — check the decoder stand-in")
	}
	if strings.Contains(url.PathEscape(spoken), "+") {
		t.Errorf("PathEscape(%q) still writes a plus", spoken)
	}
}
