package server

import (
	"fmt"

	"github.com/gin-gonic/gin"

	"scrabble/backend/internal/adminconsole"
	"scrabble/backend/internal/gamelimits"
)

// gameLimitsDTOFor resolves the caller's tier active-game caps into the profile DTO, so the client
// can lock a capped New-Game start per kind. It returns nil when the limits config is not wired.
func (s *Server) gameLimitsDTOFor(isGuest bool) *gameLimitsDTO {
	if s.gamelimits == nil {
		return nil
	}
	l := s.gamelimits.LimitsFor(isGuest)
	return &gameLimitsDTO{VsAI: l.VsAI, Random: l.Random, Friends: l.Friends}
}

// consoleLimits renders the per-tier, per-kind active-game limit form (backend.config), read from
// the in-memory cache.
func (s *Server) consoleLimits(c *gin.Context) {
	cfg := s.gamelimits.Get()
	s.renderConsole(c, "limits", "limits", "Game limits", adminconsole.GameLimitsView{
		GuestVsAI:      cfg.Guest.VsAI,
		GuestRandom:    cfg.Guest.Random,
		GuestFriends:   cfg.Guest.Friends,
		DurableVsAI:    cfg.Durable.VsAI,
		DurableRandom:  cfg.Durable.Random,
		DurableFriends: cfg.Durable.Friends,
	})
}

// consoleUpdateLimits saves the active-game limits and refreshes the hot cache in place. Each
// field is a per-kind cap: -1 is unlimited, 0 blocks the kind, a positive value caps concurrent games.
func (s *Server) consoleUpdateLimits(c *gin.Context) {
	cfg := gamelimits.Config{
		Guest: gamelimits.Limits{
			VsAI:    atoiForm(c, "guest_vs_ai"),
			Random:  atoiForm(c, "guest_random"),
			Friends: atoiForm(c, "guest_friends"),
		},
		Durable: gamelimits.Limits{
			VsAI:    atoiForm(c, "durable_vs_ai"),
			Random:  atoiForm(c, "durable_random"),
			Friends: atoiForm(c, "durable_friends"),
		},
	}
	if err := validateGameLimits(cfg); err != nil {
		s.renderConsoleMessage(c, "Invalid", err.Error(), "/_gm/limits")
		return
	}
	if err := s.gamelimits.Update(c.Request.Context(), cfg); err != nil {
		s.consoleError(c, err)
		return
	}
	s.renderConsoleMessage(c, "Saved", "game limits updated", "/_gm/limits")
}

// validateGameLimits rejects a limit below -1 (the unlimited sentinel); -1, 0 and any positive count
// are valid. It mirrors the backend.config CHECK so a bad value is refused with a clean message
// rather than a raw database error.
func validateGameLimits(cfg gamelimits.Config) error {
	for _, v := range []int{
		cfg.Guest.VsAI, cfg.Guest.Random, cfg.Guest.Friends,
		cfg.Durable.VsAI, cfg.Durable.Random, cfg.Durable.Friends,
	} {
		if v < gamelimits.Unlimited {
			return fmt.Errorf("a limit must be -1 (unlimited), 0, or a positive count")
		}
	}
	return nil
}
