package handlers import ( "encoding/json" "net/http" "strconv" "github.com/fish/language/backend/internal/models" "github.com/fish/language/backend/internal/services" "github.com/go-chi/chi/v5" ) // WordHandler handles HTTP requests for words. type WordHandler struct { svc *services.WordService } // NewWordHandler creates a new WordHandler. func NewWordHandler(svc *services.WordService) *WordHandler { return &WordHandler{svc: svc} } // Register mounts word routes. func (h *WordHandler) Register(r chi.Router) { r.Get("/words", h.List) r.Post("/words", h.Create) r.Get("/words/{id}", h.Get) r.Put("/words/{id}", h.Update) r.Delete("/words/{id}", h.Delete) } // List returns a paginated list of words. func (h *WordHandler) List(w http.ResponseWriter, r *http.Request) { req := models.ListWordsRequest{} if v := r.URL.Query().Get("category_id"); v != "" { if id64, err := strconv.ParseInt(v, 10, 32); err == nil { id := int32(id64) req.CategoryID = &id } } req.Keyword = r.URL.Query().Get("keyword") if v := r.URL.Query().Get("page"); v != "" { if page, err := strconv.ParseInt(v, 10, 32); err == nil { req.Page = int32(page) } } if v := r.URL.Query().Get("page_size"); v != "" { if ps, err := strconv.ParseInt(v, 10, 32); err == nil { req.PageSize = int32(ps) } } resp, err := h.svc.List(r.Context(), req) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, resp) } // Get returns a word by id. func (h *WordHandler) Get(w http.ResponseWriter, r *http.Request) { id, err := parseID(r) if err != nil { RespondError(w, http.StatusBadRequest, 10002, "invalid id") return } item, err := h.svc.Get(r.Context(), id) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, item) } // Create creates a new word. func (h *WordHandler) Create(w http.ResponseWriter, r *http.Request) { var req models.CreateWordRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { RespondError(w, http.StatusBadRequest, 10003, "invalid request body") return } if req.Word == "" || req.Translation == "" || req.CategoryID == 0 { RespondError(w, http.StatusBadRequest, 10004, "word, translation and category_id are required") return } item, err := h.svc.Create(r.Context(), req) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondJSON(w, http.StatusCreated, modelsAPIResponse{Code: 0, Message: "created", Data: item}) } // Update updates a word. func (h *WordHandler) Update(w http.ResponseWriter, r *http.Request) { id, err := parseID(r) if err != nil { RespondError(w, http.StatusBadRequest, 10002, "invalid id") return } var req models.UpdateWordRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { RespondError(w, http.StatusBadRequest, 10003, "invalid request body") return } if req.Word == "" || req.Translation == "" || req.CategoryID == 0 { RespondError(w, http.StatusBadRequest, 10004, "word, translation and category_id are required") return } item, err := h.svc.Update(r.Context(), id, req) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, item) } // Delete removes a word. func (h *WordHandler) Delete(w http.ResponseWriter, r *http.Request) { id, err := parseID(r) if err != nil { RespondError(w, http.StatusBadRequest, 10002, "invalid id") return } if err := h.svc.Delete(r.Context(), id); err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, nil) }