package testenv

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"testing"
)

// Pilot bundles a registered Session with its resolved user_id and a
// pre-built BackendUserClient so tests do not have to repeat the
// resolution dance for each redeem call.
type Pilot struct {
	Session  *Session
	UserID   string
	HTTP     *BackendUserClient
	RaceName string
}

// EnrollPilots registers `count` pilots with synthetic
// `Player01..PlayerNN` race names and the matching
// `playerNN+suffix@example.com` emails, then has owner issue an
// invite for each one and the pilot redeem it. The game must be in
// `enrollment_open` (or any state that accepts invites + redeem).
//
// The helper exists because the engine's `/api/v1/admin/init` enforces
// `len(races) >= 10`, so any runtime-driven scenario needs at least
// ten enrolled members. Using it from tests keeps each pilot a real
// authenticated user, exactly mirroring how operators would seed a
// production game.
func EnrollPilots(t *testing.T, plat *Platform, ownerHTTP *BackendUserClient, gameID string, count int, suffix string) []*Pilot {
	t.Helper()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	pilots := make([]*Pilot, 0, count)
	for i := 1; i <= count; i++ {
		raceName := fmt.Sprintf("Player%02d", i)
		email := fmt.Sprintf("player%02d+%s@example.com", i, suffix)

		sess := RegisterSession(t, plat, email)
		userID, err := sess.LookupUserID(ctx, plat)
		if err != nil {
			t.Fatalf("pilot %s: resolve user_id: %v", raceName, err)
		}

		raw, resp, err := ownerHTTP.Do(ctx, http.MethodPost, "/api/v1/user/lobby/games/"+gameID+"/invites", map[string]any{
			"invited_user_id": userID,
			"race_name":       raceName,
		})
		if err != nil || resp.StatusCode != http.StatusCreated {
			t.Fatalf("pilot %s: issue invite: err=%v status=%d body=%s", raceName, err, resp.StatusCode, string(raw))
		}
		var invite struct {
			InviteID string `json:"invite_id"`
		}
		if err := json.Unmarshal(raw, &invite); err != nil {
			t.Fatalf("pilot %s: decode invite: %v", raceName, err)
		}

		pilotHTTP := NewBackendUserClient(plat.Backend.HTTPURL, userID)
		raw, resp, err = pilotHTTP.Do(ctx, http.MethodPost, "/api/v1/user/lobby/games/"+gameID+"/invites/"+invite.InviteID+"/redeem", nil)
		if err != nil || resp.StatusCode/100 != 2 {
			t.Fatalf("pilot %s: redeem: err=%v status=%d body=%s", raceName, err, resp.StatusCode, string(raw))
		}

		pilots = append(pilots, &Pilot{
			Session:  sess,
			UserID:   userID,
			HTTP:     pilotHTTP,
			RaceName: raceName,
		})
	}
	return pilots
}
