1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package lunatask
6
7import (
8 "encoding/json"
9 "errors"
10 "fmt"
11 "strings"
12)
13
14// TaskStatus represents the workflow state of a task.
15//
16//nolint:recvcheck // MarshalJSON must use value receiver, UnmarshalJSON must use pointer
17type TaskStatus string
18
19// Valid task status values.
20const (
21 // StatusLater is the default status for new tasks.
22 StatusLater TaskStatus = "later"
23 StatusNext TaskStatus = "next"
24 StatusInProgress TaskStatus = "in-progress"
25 StatusWaiting TaskStatus = "waiting"
26 StatusCompleted TaskStatus = "completed"
27)
28
29// Errors returned by TaskStatus operations.
30var (
31 // ErrInvalidTaskStatus is returned when parsing an unknown task status string.
32 ErrInvalidTaskStatus = errors.New("invalid task status")
33)
34
35// String returns the task status value as a string.
36func (s TaskStatus) String() string {
37 return string(s)
38}
39
40// MarshalJSON implements [json.Marshaler].
41// Translates "in-progress" to "started" for the API.
42func (s TaskStatus) MarshalJSON() ([]byte, error) {
43 val := string(s)
44 if s == StatusInProgress {
45 val = "started"
46 }
47
48 data, err := json.Marshal(val)
49 if err != nil {
50 return nil, fmt.Errorf("marshaling task status: %w", err)
51 }
52
53 return data, nil
54}
55
56// UnmarshalJSON implements [json.Unmarshaler].
57// Translates "started" from the API to "in-progress".
58func (s *TaskStatus) UnmarshalJSON(data []byte) error {
59 var val string
60 if err := json.Unmarshal(data, &val); err != nil {
61 return fmt.Errorf("task status must be a string: %w", err)
62 }
63
64 if val == "started" {
65 *s = StatusInProgress
66
67 return nil
68 }
69
70 *s = TaskStatus(val)
71
72 return nil
73}
74
75// AllTaskStatuses returns all valid task status values in workflow order.
76func AllTaskStatuses() []TaskStatus {
77 return []TaskStatus{
78 StatusLater,
79 StatusNext,
80 StatusInProgress,
81 StatusWaiting,
82 StatusCompleted,
83 }
84}
85
86// ParseTaskStatus parses a string to a TaskStatus value (case-insensitive).
87// Valid values: "later", "next", "in-progress", "waiting", "completed".
88func ParseTaskStatus(str string) (TaskStatus, error) {
89 switch strings.ToLower(str) {
90 case "later":
91 return StatusLater, nil
92 case "next":
93 return StatusNext, nil
94 case "in-progress":
95 return StatusInProgress, nil
96 case "waiting":
97 return StatusWaiting, nil
98 case "completed":
99 return StatusCompleted, nil
100 default:
101 return "", fmt.Errorf("%w: %q", ErrInvalidTaskStatus, str)
102 }
103}