package server

import (
	"net/http"

	"galaxy/backend/internal/lobby"
	"galaxy/backend/internal/server/handlers"
	"galaxy/backend/internal/server/httperr"
	"galaxy/backend/internal/server/middleware/userid"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// UserLobbyMyHandlers groups the caller-scoped lobby read endpoints
// under `/api/v1/user/lobby/my/*`. The current implementation ships real implementations
// backed by `*lobby.Service`.
type UserLobbyMyHandlers struct {
	svc *lobby.Service
	logger *zap.Logger
}

// NewUserLobbyMyHandlers constructs the handler set. svc may be nil —
// in that case every handler returns 501 not_implemented.
func NewUserLobbyMyHandlers(svc *lobby.Service, logger *zap.Logger) *UserLobbyMyHandlers {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &UserLobbyMyHandlers{svc: svc, logger: logger.Named("http.user.lobby.my")}
}

// Games handles GET /api/v1/user/lobby/my/games.
func (h *UserLobbyMyHandlers) Games() gin.HandlerFunc {
	if h.svc == nil {
		return handlers.NotImplemented("userLobbyMyGames")
	}
	return func(c *gin.Context) {
		userID, ok := userid.FromContext(c.Request.Context())
		if !ok {
			httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, "X-User-ID header is required")
			return
		}
		ctx := c.Request.Context()
		games, err := h.svc.ListMyGames(ctx, userID)
		if err != nil {
			respondLobbyError(c, h.logger, "user lobby my games", ctx, err)
			return
		}
		out := myGamesListResponseWire{Items: make([]gameSummaryWire, 0, len(games))}
		for _, g := range games {
			out.Items = append(out.Items, gameSummaryToWire(g))
		}
		c.JSON(http.StatusOK, out)
	}
}

// Applications handles GET /api/v1/user/lobby/my/applications.
func (h *UserLobbyMyHandlers) Applications() gin.HandlerFunc {
	if h.svc == nil {
		return handlers.NotImplemented("userLobbyMyApplications")
	}
	return func(c *gin.Context) {
		userID, ok := userid.FromContext(c.Request.Context())
		if !ok {
			httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, "X-User-ID header is required")
			return
		}
		ctx := c.Request.Context()
		items, err := h.svc.ListMyApplications(ctx, userID)
		if err != nil {
			respondLobbyError(c, h.logger, "user lobby my applications", ctx, err)
			return
		}
		out := lobbyApplicationListWire{Items: make([]lobbyApplicationDetailWire, 0, len(items))}
		for _, a := range items {
			out.Items = append(out.Items, lobbyApplicationDetailToWire(a))
		}
		c.JSON(http.StatusOK, out)
	}
}

// Invites handles GET /api/v1/user/lobby/my/invites.
func (h *UserLobbyMyHandlers) Invites() gin.HandlerFunc {
	if h.svc == nil {
		return handlers.NotImplemented("userLobbyMyInvites")
	}
	return func(c *gin.Context) {
		userID, ok := userid.FromContext(c.Request.Context())
		if !ok {
			httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, "X-User-ID header is required")
			return
		}
		ctx := c.Request.Context()
		items, err := h.svc.ListMyInvites(ctx, userID)
		if err != nil {
			respondLobbyError(c, h.logger, "user lobby my invites", ctx, err)
			return
		}
		out := lobbyInviteListWire{Items: make([]lobbyInviteDetailWire, 0, len(items))}
		for _, i := range items {
			out.Items = append(out.Items, lobbyInviteDetailToWire(i))
		}
		c.JSON(http.StatusOK, out)
	}
}

// RaceNames handles GET /api/v1/user/lobby/my/race-names.
func (h *UserLobbyMyHandlers) RaceNames() gin.HandlerFunc {
	if h.svc == nil {
		return handlers.NotImplemented("userLobbyMyRaceNames")
	}
	return func(c *gin.Context) {
		userID, ok := userid.FromContext(c.Request.Context())
		if !ok {
			httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, "X-User-ID header is required")
			return
		}
		ctx := c.Request.Context()
		items, err := h.svc.ListMyRaceNames(ctx, userID)
		if err != nil {
			respondLobbyError(c, h.logger, "user lobby my race-names", ctx, err)
			return
		}
		out := raceNameListWire{Items: make([]raceNameDetailWire, 0, len(items))}
		for _, e := range items {
			out.Items = append(out.Items, raceNameDetailToWire(e))
		}
		c.JSON(http.StatusOK, out)
	}
}

// Wire envelopes for caller-scoped lists.

// myGamesListResponseWire mirrors `MyGamesListResponse`.
type myGamesListResponseWire struct {
	Items []gameSummaryWire `json:"items"`
}

// lobbyApplicationListWire mirrors `LobbyApplicationList`.
type lobbyApplicationListWire struct {
	Items []lobbyApplicationDetailWire `json:"items"`
}

// lobbyInviteListWire mirrors `LobbyInviteList`.
type lobbyInviteListWire struct {
	Items []lobbyInviteDetailWire `json:"items"`
}

// raceNameListWire mirrors `RaceNameList`.
type raceNameListWire struct {
	Items []raceNameDetailWire `json:"items"`
}
