package api import ( "log/slog" "net/http" "messenger/internal/auth" "messenger/internal/platform/config" "messenger/internal/realtime" "messenger/internal/store" ) type apiHandler struct { store *store.Store tokens *auth.TokenManager hub *realtime.Hub log *slog.Logger secure bool } // NewHandler builds the /api/v1 route tree with all middleware applied. func NewHandler(st *store.Store, tm *auth.TokenManager, hub *realtime.Hub, log *slog.Logger, cfg *config.Config) http.Handler { h := &apiHandler{ store: st, tokens: tm, hub: hub, log: log, secure: cfg.Environment == "production", } mux := http.NewServeMux() authHandler := requireAuth(tm, http.HandlerFunc(h.websocket)) mux.HandleFunc("GET /api/v1/ping", func(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]string{"message": "pong"}) }) mux.HandleFunc("POST /api/v1/auth/register", h.register) mux.HandleFunc("POST /api/v1/auth/login", h.login) mux.HandleFunc("POST /api/v1/auth/refresh", h.refresh) mux.HandleFunc("POST /api/v1/auth/logout", h.logout) mux.Handle("GET /api/v1/users/me", requireAuth(tm, h.me)) mux.Handle("GET /api/v1/users", requireAuth(tm, h.searchUsers)) mux.Handle("GET /api/v1/contacts", requireAuth(tm, h.listContacts)) mux.Handle("POST /api/v1/contacts", requireAuth(tm, h.addContact)) mux.Handle("DELETE /api/v1/contacts/{user_id}", requireAuth(tm, h.removeContact)) mux.Handle("GET /api/v1/conversations", requireAuth(tm, h.listConversations)) mux.Handle("POST /api/v1/conversations", requireAuth(tm, h.createDM)) mux.Handle("GET /api/v1/conversations/{id}/messages", requireAuth(tm, h.listMessages)) mux.Handle("POST /api/v1/conversations/{id}/messages", requireAuth(tm, h.sendMessage)) mux.Handle("GET /ws", authHandler) return mux } func (h *apiHandler) websocket(w http.ResponseWriter, r *http.Request) { userID, ok := userIDFrom(r.Context()) if !ok { writeError(w, http.StatusUnauthorized, "unauthenticated") return } h.hub.HandleWS(w, r, userID) }