package handlers import ( "encoding/json" "log" "net/http" "github.com/gorilla/mux" gorillaWs "github.com/gorilla/websocket" "github.com/frisbee-tournament/backend/internal/models" "github.com/frisbee-tournament/backend/internal/storage" ws "github.com/frisbee-tournament/backend/internal/websocket" ) type Handler struct { store *storage.Store hubMgr *ws.HubManager } func New(store *storage.Store, hubMgr *ws.HubManager) *Handler { return &Handler{store: store, hubMgr: hubMgr} } var upgrader = gorillaWs.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true // trust-based, no auth }, } func writeJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(v) } func writeError(w http.ResponseWriter, status int, msg string) { writeJSON(w, status, map[string]string{"error": msg}) } // --- Tournament endpoints --- func (h *Handler) ListTournaments(w http.ResponseWriter, r *http.Request) { ts, err := h.store.GetTournaments() if err != nil { writeError(w, 500, err.Error()) return } writeJSON(w, 200, ts) } func (h *Handler) GetTournament(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] t, err := h.store.GetTournament(id) if err != nil { writeError(w, 404, err.Error()) return } writeJSON(w, 200, t) } // --- Schedule --- func (h *Handler) GetSchedule(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] sched, err := h.store.GetSchedule(id) if err != nil { writeError(w, 500, err.Error()) return } // Merge persisted scores into schedule games for i := range sched.Games { g := &sched.Games[i] state, err := h.store.GetScore(id, g.ID) if err == nil && state.Status != "" { g.HomeScore = state.HomeScore g.AwayScore = state.AwayScore g.Status = state.Status } } writeJSON(w, 200, sched) } // --- Scoring --- func (h *Handler) GetScore(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) state, err := h.store.GetScore(vars["id"], vars["gid"]) if err != nil { writeError(w, 500, err.Error()) return } writeJSON(w, 200, state) } func (h *Handler) UpdateScore(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) var update models.ScoreUpdate if err := json.NewDecoder(r.Body).Decode(&update); err != nil { writeError(w, 400, "invalid request body") return } hub := h.hubMgr.GetOrCreateHub(vars["id"], vars["gid"]) state, err := hub.HandleScoreUpdate(update) if err != nil { writeError(w, 500, err.Error()) return } writeJSON(w, 200, state) } func (h *Handler) GetAuditLog(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) entries, err := h.store.GetAuditLog(vars["id"], vars["gid"]) if err != nil { writeError(w, 500, err.Error()) return } if entries == nil { entries = []models.AuditEntry{} } writeJSON(w, 200, entries) } // --- WebSocket --- func (h *Handler) WebSocketHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("ws upgrade error: %v", err) return } userID := r.URL.Query().Get("user_id") if userID == "" { userID = "anonymous" } hub := h.hubMgr.GetOrCreateHub(vars["id"], vars["gid"]) client := hub.RegisterClient(conn, userID) go client.WritePump() go client.ReadPump() } func (h *Handler) TournamentWebSocketHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("ws upgrade error: %v", err) return } th := h.hubMgr.GetOrCreateTournamentHub(vars["id"]) client := th.RegisterClient(conn) go client.WritePump() go client.ReadPumpTournament(th) } // --- Questionnaire --- func (h *Handler) GetQuestionnaire(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] cfg, err := h.store.GetQuestionnaireConfig(id) if err != nil { writeError(w, 500, err.Error()) return } t, _ := h.store.GetTournament(id) resp := map[string]any{ "config": cfg, } if t != nil { resp["teams"] = t.Teams } writeJSON(w, 200, resp) } func (h *Handler) SubmitQuestionnaire(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] var resp models.QuestionnaireResponse if err := json.NewDecoder(r.Body).Decode(&resp); err != nil { writeError(w, 400, "invalid request body") return } resp.TourneyID = id if err := h.store.SaveQuestionnaireResponse(id, &resp); err != nil { writeError(w, 500, err.Error()) return } writeJSON(w, 201, map[string]string{"status": "ok", "id": resp.ID}) } func (h *Handler) GetQuestionnaireResults(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] resps, err := h.store.GetQuestionnaireResponses(id) if err != nil { writeError(w, 500, err.Error()) return } if resps == nil { resps = []models.QuestionnaireResponse{} } writeJSON(w, 200, resps) } // --- Results --- func (h *Handler) GetResults(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] res, err := h.store.GetResults(id) if err != nil { writeError(w, 500, err.Error()) return } writeJSON(w, 200, res) }