package lobby

import (
	"time"

	"github.com/google/uuid"
)

// GameRecord mirrors a row in `backend.games` enriched with the
// denormalised runtime snapshot fields persisted in the same row. The
// JSON-encoded `runtime_snapshot` column is decoded into RuntimeSnapshot
// before reaching this struct.
type GameRecord struct {
	GameID uuid.UUID
	OwnerUserID *uuid.UUID
	Visibility string
	Status string
	GameName string
	Description string
	MinPlayers int32
	MaxPlayers int32
	StartGapHours int32
	StartGapPlayers int32
	EnrollmentEndsAt time.Time
	TurnSchedule string
	TargetEngineVersion string
	RuntimeSnapshot RuntimeSnapshot
	CreatedAt time.Time
	UpdatedAt time.Time
	StartedAt *time.Time
	FinishedAt *time.Time
}

// RuntimeSnapshot is the lobby's denormalised view of the runtime state
// reported by the runtime module. The current implementation ships placeholder values
// (zero CurrentTurn, empty RuntimeStatus) until the canonical implementation wires
// `OnRuntimeSnapshot`.
type RuntimeSnapshot struct {
	CurrentTurn int32 `json:"current_turn"`
	RuntimeStatus string `json:"runtime_status,omitempty"`
	EngineHealth string `json:"engine_health,omitempty"`
	PlayerStats []PlayerTurnStats `json:"player_stats,omitempty"`
	ObservedAt time.Time `json:"observed_at,omitempty"`
}

// PlayerTurnStats is the per-player observation read from a runtime
// snapshot. Lobby aggregates `MaxPlanets` / `MaxPopulation` across the
// game lifetime to evaluate capable-finish at `OnGameFinished`.
type PlayerTurnStats struct {
	UserID uuid.UUID `json:"user_id"`
	InitialPlanets int32 `json:"initial_planets"`
	InitialPopulation int32 `json:"initial_population"`
	CurrentPlanets int32 `json:"current_planets"`
	CurrentPopulation int32 `json:"current_population"`
	MaxPlanets int32 `json:"max_planets"`
	MaxPopulation int32 `json:"max_population"`
}

// Application mirrors a row in `backend.applications`.
type Application struct {
	ApplicationID uuid.UUID
	GameID uuid.UUID
	ApplicantUserID uuid.UUID
	RaceName string
	Status string
	CreatedAt time.Time
	DecidedAt *time.Time
}

// Invite mirrors a row in `backend.invites`. `InvitedUserID` is nil for
// code-based invites; `Code` is non-empty for those.
type Invite struct {
	InviteID uuid.UUID
	GameID uuid.UUID
	InviterUserID uuid.UUID
	InvitedUserID *uuid.UUID
	Code string
	Status string
	RaceName string
	CreatedAt time.Time
	ExpiresAt time.Time
	DecidedAt *time.Time
}

// Membership mirrors a row in `backend.memberships`. `CanonicalKey` is
// the canonical form of `RaceName` produced by the Race Name Directory
// policy at write time.
type Membership struct {
	MembershipID uuid.UUID
	GameID uuid.UUID
	UserID uuid.UUID
	RaceName string
	CanonicalKey string
	Status string
	JoinedAt time.Time
	RemovedAt *time.Time
}

// RaceNameEntry mirrors a row in `backend.race_names`.
//
// Status `registered` rows store the all-zero sentinel UUID in `GameID`
// so the partial UNIQUE index `race_names_registered_uidx` covers the
// uniqueness rule. Status `reservation` and `pending_registration` rows
// store the originating `game_id`.
type RaceNameEntry struct {
	Name string
	Canonical CanonicalKey
	Status string
	OwnerUserID uuid.UUID
	GameID uuid.UUID
	SourceGameID *uuid.UUID
	ReservedAt *time.Time
	ExpiresAt *time.Time
	RegisteredAt *time.Time
}

// IsRegistered reports whether the entry is platform-permanent.
func (e RaceNameEntry) IsRegistered() bool {
	return e.Status == RaceNameStatusRegistered
}

// IsReservation reports whether the entry binds the canonical key to a
// concrete game without permanent ownership.
func (e RaceNameEntry) IsReservation() bool {
	return e.Status == RaceNameStatusReservation
}

// IsPending reports whether the entry is awaiting capable-finish
// registration.
func (e RaceNameEntry) IsPending() bool {
	return e.Status == RaceNameStatusPendingRegistration
}

// raceNameRegisteredGameSentinel is the sentinel UUID stored in
// `race_names.game_id` for `registered` rows. Mirrors the migration's
// `DEFAULT '00000000-0000-0000-0000-000000000000'` clause.
var raceNameRegisteredGameSentinel = uuid.UUID{}
