package handlers import ( "go-server/internal/models" "go-server/internal/service" "net/http" "strconv" "time" "github.com/gin-gonic/gin" ) type TodoController struct { service *service.TodoService } func NewTodoController(service *service.TodoService) *TodoController { return &TodoController{ service: service, } } // CreateTodo creates a new todo // POST /api/todo/create func (h *TodoController) CreateTodo(c *gin.Context) { userID := getUserIDFromContext(c) // You'll need to implement this helper if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } var req service.CreateTodoRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } todo, err := h.service.CreateTodo(c.Request.Context(), userID, req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create todo"}) return } c.JSON(http.StatusCreated, todo) } // GetTodos gets all todos with stats for the authenticated user // GET /api/todo/list func (h *TodoController) GetTodos(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } todos, err := h.service.GetTodosWithStats(c.Request.Context(), userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get todos"}) return } c.JSON(http.StatusOK, todos) } // GetTodaysSummary gets today's todo summary // GET /api/todo/today func (h *TodoController) GetTodaysSummary(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } summary, err := h.service.GetTodaysSummary(c.Request.Context(), userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get today's summary"}) return } c.JSON(http.StatusOK, summary) } // UpdateTodo updates a todo // PUT /api/todo/:id func (h *TodoController) UpdateTodo(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } todoIDStr := c.Param("id") todoID, err := models.ParseULID(todoIDStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid todo ID"}) return } var req service.UpdateTodoRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } todo, err := h.service.UpdateTodo(c.Request.Context(), todoID, userID, req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update todo"}) return } c.JSON(http.StatusOK, todo) } // DeleteTodo deletes a todo // DELETE /api/todo/:id func (h *TodoController) DeleteTodo(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } todoIDStr := c.Param("id") todoID, err := models.ParseULID(todoIDStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid todo ID"}) return } err = h.service.DeleteTodo(c.Request.Context(), todoID, userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete todo"}) return } c.JSON(http.StatusOK, gin.H{"message": "Todo deleted successfully"}) } // CompleteTodo marks a todo as completed // POST /api/todo/:id/complete func (h *TodoController) CompleteTodo(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } todoIDStr := c.Param("id") todoID, err := models.ParseULID(todoIDStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid todo ID"}) return } var req service.CompleteTodoRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } err = h.service.CompleteTodo(c.Request.Context(), todoID, userID, req) if err != nil { if err.Error() == "todo already completed today" { c.JSON(http.StatusConflict, gin.H{"error": "Todo already completed today"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to complete todo"}) return } c.JSON(http.StatusOK, gin.H{"message": "Todo completed successfully"}) } // GetActivityLog gets the user's activity log // GET /api/todo/activity func (h *TodoController) GetActivityLog(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } // Parse pagination parameters limitStr := c.DefaultQuery("limit", "50") offsetStr := c.DefaultQuery("offset", "0") limit, err := strconv.Atoi(limitStr) if err != nil { limit = 50 } offset, err := strconv.Atoi(offsetStr) if err != nil { offset = 0 } activities, err := h.service.GetActivityLog(c.Request.Context(), userID, limit, offset) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get activity log"}) return } c.JSON(http.StatusOK, activities) } // GetActivityLogByDate gets activity log for a specific date // GET /api/todo/activity/:date func (h *TodoController) GetActivityLogByDate(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } dateStr := c.Param("date") date, err := time.Parse("2006-01-02", dateStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid date format. Use YYYY-MM-DD"}) return } activities, err := h.service.GetActivityLogByDate(c.Request.Context(), userID, date) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get activity log"}) return } c.JSON(http.StatusOK, activities) } // GetWeeklySummary gets a weekly summary of todo completions // GET /api/todo/weekly func (h *TodoController) GetWeeklySummary(c *gin.Context) { userID := getUserIDFromContext(c) if userID.IsZero() { c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"}) return } summary, err := h.service.GetWeeklySummary(c.Request.Context(), userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get weekly summary"}) return } c.JSON(http.StatusOK, summary) } // Helper function to get user ID from context // You'll need to implement this based on your authentication middleware func getUserIDFromContext(c *gin.Context) models.ULID { testUserId := models.MustParseULID("01K54QBS528HKQDF985XNW2J6R") return testUserId // This is a placeholder - implement based on your auth system // For example, if you store the user in context after JWT validation: // userInterface, exists := c.Get("user") // if !exists { // return models.ULID{} // Return zero value // } // user, ok := userInterface.(*models.User) // if !ok { // return models.ULID{} // Return zero value // } // return user.ID }