package main

import (
	"html"
	"io"
	"net/http"
	"net/http/httptest"
	"net/url"
	"regexp"
	"testing"
	"time"
)

// formHxGetRe extracts the hx-get URL of a slot button pointing at /form.
var formHxGetRe = regexp.MustCompile(`hx-get="([^"]*/form[^"]*)"`)

// TestHandleGetSlots_OffsetSlotStartSurvivesURLParsing pins the bidbuddy.com.au
// (Australia/Perth) production failure: Cal.com returns slot starts in the
// event's own timezone with a numeric `+08:00` offset. That value is carried in
// the slot button's hx-get query string; a raw `+` in a query string decodes to
// a SPACE server-side, corrupting the timestamp ("2026-06-11T10:00:00 08:00").
// The corrupted value flows form → book → Cal.com, which rejects it with
// "start must be a valid ISO 8601 date string". The slot's machine value must
// therefore round-trip through URL query parsing as a valid RFC3339 timestamp.
func TestHandleGetSlots_OffsetSlotStartSurvivesURLParsing(t *testing.T) {
	// 2026-06-11T10:00:00+08:00 (Perth) == 2026-06-11T02:00:00Z.
	fakeCalcom(t, "Australia/Perth", func(w http.ResponseWriter, _ *http.Request) {
		_, _ = io.WriteString(w, `{
			"status":"success",
			"data":{"2026-06-11":[{"start":"2026-06-11T10:00:00+08:00"}]}
		}`)
	})
	h, _ := newKeyedHandler(t)

	req := httptest.NewRequest(http.MethodGet,
		"/slots?username=alice&eventType=30min&date=2026-06-11&blockId=b1", nil)
	rec := httptest.NewRecorder()
	h.HandleGetSlots(rec, req)

	if rec.Code != http.StatusOK {
		t.Fatalf("expected 200, got %d (body: %s)", rec.Code, rec.Body.String())
	}

	m := formHxGetRe.FindStringSubmatch(rec.Body.String())
	if m == nil {
		t.Fatalf("no slot button hx-get to /form found in body: %q", rec.Body.String())
	}
	// The browser reads the attribute via the DOM, which unescapes &amp; → &.
	u, err := url.Parse(html.UnescapeString(m[1]))
	if err != nil {
		t.Fatalf("parse slot form URL %q: %v", m[1], err)
	}

	// u.Query() decodes exactly as net/http would on the wire — this is where a
	// raw `+` becomes a space.
	got := u.Query().Get("start")
	parsed, err := time.Parse(time.RFC3339, got)
	if err != nil {
		t.Fatalf("slot start %q is not a valid ISO 8601 string after URL parsing (Cal.com would reject it): %v", got, err)
	}
	if want := time.Date(2026, 6, 11, 2, 0, 0, 0, time.UTC); !parsed.Equal(want) {
		t.Errorf("slot start instant: got %s, want %s", parsed.UTC(), want)
	}
}
