1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package lunatask
6
7import "time"
8
9// TaskFilterOptions configures task list filtering.
10type TaskFilterOptions struct {
11 AreaID *string
12 GoalID *string
13 Status *TaskStatus
14 IncludeCompleted bool // If false, excludes completed tasks older than Today
15 Today time.Time // Reference date for "old completed" check
16}
17
18// FilterTasks returns tasks matching the given filter options.
19// If opts is nil, returns all tasks unchanged.
20func FilterTasks(tasks []Task, opts *TaskFilterOptions) []Task {
21 if opts == nil {
22 return tasks
23 }
24
25 filtered := make([]Task, 0, len(tasks))
26
27 for _, task := range tasks {
28 if matchesFilter(task, opts) {
29 filtered = append(filtered, task)
30 }
31 }
32
33 return filtered
34}
35
36func matchesFilter(task Task, opts *TaskFilterOptions) bool {
37 if !matchesAreaFilter(task, opts.AreaID) {
38 return false
39 }
40
41 if !matchesGoalFilter(task, opts.GoalID) {
42 return false
43 }
44
45 if !matchesStatusFilter(task, opts.Status) {
46 return false
47 }
48
49 if !opts.IncludeCompleted && opts.Status == nil && IsOldCompleted(task, opts.Today) {
50 return false
51 }
52
53 return true
54}
55
56func matchesAreaFilter(task Task, areaID *string) bool {
57 if areaID == nil {
58 return true
59 }
60
61 return task.AreaID != nil && *task.AreaID == *areaID
62}
63
64func matchesGoalFilter(task Task, goalID *string) bool {
65 if goalID == nil {
66 return true
67 }
68
69 return task.GoalID != nil && *task.GoalID == *goalID
70}
71
72func matchesStatusFilter(task Task, status *TaskStatus) bool {
73 if status == nil {
74 return true
75 }
76
77 return task.Status != nil && *task.Status == *status
78}
79
80// IsOldCompleted returns true if the task was completed before the given date.
81// Returns false for non-completed tasks or tasks with no CompletedAt timestamp.
82func IsOldCompleted(task Task, today time.Time) bool {
83 if task.Status == nil || *task.Status != StatusCompleted {
84 return false
85 }
86
87 return task.CompletedAt == nil || task.CompletedAt.Before(today)
88}