package handlers import ( "math/rand" "net/http" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/toyffee/party-mix/internal/models" "gorm.io/gorm" ) const codeChars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" func generateCode() string { b := make([]byte, 6) for i := range b { b[i] = codeChars[rand.Intn(len(codeChars))] } return string(b) } type createPartyReq struct { Name string `json:"name" binding:"required"` TelegramID int64 `json:"telegram_id"` } func CreateParty(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var req createPartyReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } party := models.Party{ ID: uuid.NewString(), Name: req.Name, Code: generateCode(), TelegramID: req.TelegramID, CreatedAt: time.Now(), } if err := db.Create(&party).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create party"}) return } c.JSON(http.StatusCreated, party) } } func GetParty(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var party models.Party err := db.Preload("Participants.Tracks").First(&party, "id = ?", c.Param("id")).Error if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "party not found"}) return } c.JSON(http.StatusOK, party) } } func GetPartyByCode(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var party models.Party err := db.Preload("Participants.Tracks").First(&party, "code = ?", c.Param("code")).Error if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "party not found"}) return } c.JSON(http.StatusOK, party) } } type addParticipantReq struct { Name string `json:"name" binding:"required"` Tracks []string `json:"tracks" binding:"required"` ColorBg string `json:"color_bg"` ColorText string `json:"color_text"` } func AddParticipant(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var req addParticipantReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } participant := models.Participant{ ID: uuid.NewString(), PartyID: c.Param("id"), Name: req.Name, ColorBg: req.ColorBg, ColorText: req.ColorText, CreatedAt: time.Now(), } tracks := make([]models.Track, 0, len(req.Tracks)) for i, title := range req.Tracks { tracks = append(tracks, models.Track{ ID: uuid.NewString(), ParticipantID: participant.ID, Title: title, Position: i, CreatedAt: time.Now(), }) } participant.Tracks = tracks if err := db.Create(&participant).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to add participant"}) return } c.JSON(http.StatusCreated, participant) } } func RemoveParticipant(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { pid := c.Param("pid") db.Where("participant_id = ?", pid).Delete(&models.Track{}) if err := db.Delete(&models.Participant{}, "id = ?", pid).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove participant"}) return } c.Status(http.StatusNoContent) } } type addHistoryReq struct { Title string `json:"title"` Artist string `json:"artist"` ImgURL string `json:"img_url"` OwnerName string `json:"owner_name"` OwnerColorBg string `json:"owner_color_bg"` OwnerColorText string `json:"owner_color_text"` } func AddHistory(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var req addHistoryReq if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } item := models.HistoryItem{ ID: uuid.NewString(), PartyID: c.Param("id"), Title: req.Title, Artist: req.Artist, ImgURL: req.ImgURL, OwnerName: req.OwnerName, OwnerColorBg: req.OwnerColorBg, OwnerColorText: req.OwnerColorText, PlayedAt: time.Now(), } db.Create(&item) c.JSON(http.StatusCreated, item) } } func GetHistory(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { var items []models.HistoryItem db.Where("party_id = ?", c.Param("id")).Order("played_at desc").Limit(100).Find(&items) c.JSON(http.StatusOK, items) } } func ClearHistory(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { db.Where("party_id = ?", c.Param("id")).Delete(&models.HistoryItem{}) c.Status(http.StatusNoContent) } }