package transcode_test

import (
	"context"
	"net/http"
	"testing"

	"scrabble/gateway/internal/transcode"
	fb "scrabble/pkg/fbs/scrabblefb"
)

// TestProfileGetEncodesBanner verifies the gateway forwards the backend's banner
// block verbatim into the Profile payload: the campaigns (weight + resolved
// messages, in order) and the global display timings.
func TestProfileGetEncodesBanner(t *testing.T) {
	backend, cleanup := fakeBackend(t, func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet || r.URL.Path != "/api/v1/user/profile" {
			t.Errorf("unexpected %s %q", r.Method, r.URL.Path)
		}
		_, _ = w.Write([]byte(`{"user_id":"u-1","display_name":"Kaya","preferred_language":"en",` +
			`"banner":{"campaigns":[` +
			`{"weight":3,"messages":["promo-en"]},` +
			`{"weight":7,"messages":["house-a","house-b"]}],` +
			`"timings":{"hold_ms":60000,"edge_pause_ms":5000,"scroll_px_per_sec":40,` +
			`"fade_out_ms":1000,"gap_ms":250,"fade_in_ms":1000}}}`))
	})
	defer cleanup()

	reg := transcode.NewRegistry(backend, nil)
	op, ok := reg.Lookup(transcode.MsgProfileGet)
	if !ok {
		t.Fatal("profile.get not registered")
	}
	payload, err := op.Handler(context.Background(), transcode.Request{UserID: "u-1"})
	if err != nil {
		t.Fatalf("handler: %v", err)
	}

	p := fb.GetRootAsProfile(payload, 0)
	banner := p.Banner(nil)
	if banner == nil {
		t.Fatal("profile carries no banner block")
	}
	if got := banner.CampaignsLength(); got != 2 {
		t.Fatalf("campaigns = %d, want 2", got)
	}
	var c fb.BannerCampaign
	banner.Campaigns(&c, 0)
	if c.Weight() != 3 || c.MessagesLength() != 1 || string(c.Messages(0)) != "promo-en" {
		t.Errorf("campaign 0 = weight %d, %d msgs, msg0=%q", c.Weight(), c.MessagesLength(), c.Messages(0))
	}
	banner.Campaigns(&c, 1)
	if c.Weight() != 7 || c.MessagesLength() != 2 || string(c.Messages(1)) != "house-b" {
		t.Errorf("campaign 1 = weight %d, %d msgs, msg1=%q", c.Weight(), c.MessagesLength(), c.Messages(1))
	}
	if banner.HoldMs() != 60000 || banner.EdgePauseMs() != 5000 || banner.ScrollPxPerSec() != 40 {
		t.Errorf("timings = hold %d edge %d scroll %d", banner.HoldMs(), banner.EdgePauseMs(), banner.ScrollPxPerSec())
	}
	if banner.FadeOutMs() != 1000 || banner.GapMs() != 250 || banner.FadeInMs() != 1000 {
		t.Errorf("fade timings = out %d gap %d in %d", banner.FadeOutMs(), banner.GapMs(), banner.FadeInMs())
	}
}

// TestProfileGetEncodesBannerColors verifies the gateway carries a campaign's
// optional colour overrides into the FlatBuffers payload, and leaves an absent
// colour (or an absent set) empty so the client falls back to the theme tokens.
func TestProfileGetEncodesBannerColors(t *testing.T) {
	backend, cleanup := fakeBackend(t, func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`{"user_id":"u-1","display_name":"Kaya","preferred_language":"en",` +
			`"banner":{"campaigns":[` +
			`{"weight":1,"messages":["promo-en"],` +
			`"override_bg":"#aa0000","override_fg":"#ffffff","override_link":"#ffdd00",` +
			`"override_bg_dark":"#330000","override_fg_dark":"#eeeeee","override_link_dark":"#ffcc00"},` +
			`{"weight":1,"messages":["plain-en"]}],` +
			`"timings":{"hold_ms":60000,"edge_pause_ms":5000,"scroll_px_per_sec":40,` +
			`"fade_out_ms":1000,"gap_ms":250,"fade_in_ms":1000}}}`))
	})
	defer cleanup()

	reg := transcode.NewRegistry(backend, nil)
	op, _ := reg.Lookup(transcode.MsgProfileGet)
	payload, err := op.Handler(context.Background(), transcode.Request{UserID: "u-1"})
	if err != nil {
		t.Fatalf("handler: %v", err)
	}
	banner := fb.GetRootAsProfile(payload, 0).Banner(nil)
	if banner == nil {
		t.Fatal("profile carries no banner block")
	}
	var c fb.BannerCampaign
	banner.Campaigns(&c, 0)
	if got := string(c.OverrideBg()); got != "#aa0000" {
		t.Errorf("override_bg = %q, want #aa0000", got)
	}
	if got := string(c.OverrideLink()); got != "#ffdd00" {
		t.Errorf("override_link = %q, want #ffdd00", got)
	}
	if got := string(c.OverrideBgDark()); got != "#330000" {
		t.Errorf("override_bg_dark = %q, want #330000", got)
	}
	if got := string(c.OverrideLinkDark()); got != "#ffcc00" {
		t.Errorf("override_link_dark = %q, want #ffcc00", got)
	}
	// The second campaign has no override: every colour field must be absent (nil).
	banner.Campaigns(&c, 1)
	if c.OverrideBg() != nil || c.OverrideFg() != nil || c.OverrideLink() != nil ||
		c.OverrideBgDark() != nil || c.OverrideFgDark() != nil || c.OverrideLinkDark() != nil {
		t.Error("plain campaign unexpectedly carries a colour override")
	}
}

// TestProfileGetNoBanner verifies an ineligible viewer's profile carries no
// banner block (the backend omits it).
func TestProfileGetNoBanner(t *testing.T) {
	backend, cleanup := fakeBackend(t, func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`{"user_id":"u-1","display_name":"Kaya","preferred_language":"en"}`))
	})
	defer cleanup()

	reg := transcode.NewRegistry(backend, nil)
	op, _ := reg.Lookup(transcode.MsgProfileGet)
	payload, err := op.Handler(context.Background(), transcode.Request{UserID: "u-1"})
	if err != nil {
		t.Fatalf("handler: %v", err)
	}
	if p := fb.GetRootAsProfile(payload, 0); p.Banner(nil) != nil {
		t.Error("ineligible profile unexpectedly carries a banner block")
	}
}
