package service import ( "context" "errors" "go-server/internal/models" "go-server/internal/repository" "time" ) type TodoService struct { todoRepo *repository.TodoRepository } func NewTodoService(todoRepo *repository.TodoRepository) *TodoService { return &TodoService{ todoRepo: todoRepo, } } // CreateTodoRequest represents the request to create a new todo type CreateTodoRequest struct { Title string `json:"title" validate:"required,min=1,max=200"` Description string `json:"description" validate:"max=1000"` Color string `json:"color" validate:"required,hexcolor"` } // UpdateTodoRequest represents the request to update a todo type UpdateTodoRequest struct { Title string `json:"title" validate:"required,min=1,max=200"` Description string `json:"description" validate:"max=1000"` Color string `json:"color" validate:"required,hexcolor"` } // CompleteTodoRequest represents the request to complete a todo type CompleteTodoRequest struct { Description string `json:"description" validate:"max=1000"` } // CreateTodo creates a new todo for a user func (s *TodoService) CreateTodo(ctx context.Context, userID models.ULID, req CreateTodoRequest) (*models.Todo, error) { todo := &models.Todo{ UserID: userID, Title: req.Title, Description: req.Description, Color: req.Color, IsActive: true, } err := s.todoRepo.CreateTodo(ctx, todo) if err != nil { return nil, err } return todo, nil } // GetTodosWithStats gets all todos for a user with completion statistics func (s *TodoService) GetTodosWithStats(ctx context.Context, userID models.ULID) ([]models.TodoWithStats, error) { return s.todoRepo.GetTodosWithStats(ctx, userID) } // GetTodoByID gets a todo by ID (with user verification) func (s *TodoService) GetTodoByID(ctx context.Context, todoID, userID models.ULID) (*models.Todo, error) { return s.todoRepo.GetTodoByID(ctx, todoID, userID) } // UpdateTodo updates a todo func (s *TodoService) UpdateTodo(ctx context.Context, todoID, userID models.ULID, req UpdateTodoRequest) (*models.Todo, error) { todo, err := s.todoRepo.GetTodoByID(ctx, todoID, userID) if err != nil { return nil, err } todo.Title = req.Title todo.Description = req.Description todo.Color = req.Color err = s.todoRepo.UpdateTodo(ctx, todo) if err != nil { return nil, err } return todo, nil } // DeleteTodo deletes (deactivates) a todo func (s *TodoService) DeleteTodo(ctx context.Context, todoID, userID models.ULID) error { return s.todoRepo.DeleteTodo(ctx, todoID, userID) } // CompleteTodo marks a todo as completed for today func (s *TodoService) CompleteTodo(ctx context.Context, todoID, userID models.ULID, req CompleteTodoRequest) error { // First check if the todo exists and belongs to the user todo, err := s.todoRepo.GetTodoByID(ctx, todoID, userID) if err != nil { return err } // Check if already completed today completedToday, err := s.todoRepo.CheckTodoCompletedToday(ctx, todoID, userID) if err != nil { return err } if completedToday { return errors.New("todo already completed today") } // Create completion record completion := &models.TodoCompletion{ TodoID: todo.ID, UserID: userID, CompletedAt: time.Now(), Description: req.Description, } return s.todoRepo.CompleteTodo(ctx, completion) } // GetTodaysSummary gets today's todo summary func (s *TodoService) GetTodaysSummary(ctx context.Context, userID models.ULID) (*models.DailyTodoSummary, error) { todos, err := s.todoRepo.GetTodosWithStats(ctx, userID) if err != nil { return nil, err } completedCount := 0 for _, todo := range todos { if todo.CompletedToday { completedCount++ } } summary := &models.DailyTodoSummary{ Date: time.Now(), Todos: todos, CompletedCount: completedCount, TotalCount: len(todos), } return summary, nil } // GetActivityLog gets the user's activity log with pagination func (s *TodoService) GetActivityLog(ctx context.Context, userID models.ULID, limit, offset int) ([]models.TodoCompletion, error) { if limit <= 0 { limit = 50 // Default limit } if limit > 200 { limit = 200 // Max limit } return s.todoRepo.GetActivityLog(ctx, userID, limit, offset) } // GetActivityLogByDate gets activity log for a specific date func (s *TodoService) GetActivityLogByDate(ctx context.Context, userID models.ULID, date time.Time) ([]models.TodoCompletion, error) { return s.todoRepo.GetActivityLogByDate(ctx, userID, date) } // GetWeeklySummary gets a summary of the past 7 days func (s *TodoService) GetWeeklySummary(ctx context.Context, userID models.ULID) (map[string][]models.TodoCompletion, error) { endDate := time.Now().Add(24 * time.Hour) // Include today startDate := endDate.Add(-7 * 24 * time.Hour) // 7 days ago completions, err := s.todoRepo.GetCompletionsByDateRange(ctx, userID, startDate, endDate) if err != nil { return nil, err } // Group by date dailyCompletions := make(map[string][]models.TodoCompletion) for _, completion := range completions { dateKey := completion.CompletedAt.Format("2006-01-02") dailyCompletions[dateKey] = append(dailyCompletions[dateKey], completion) } return dailyCompletions, nil }