package engine import ( "fmt" "strconv" "time" ) // ParseRecurrencePattern converts "1w", "2d", "1m" to time.Duration func ParseRecurrencePattern(pattern string) (time.Duration, error) { if len(pattern) < 2 { return 0, fmt.Errorf("invalid recurrence pattern: %s", pattern) } numStr := pattern[:len(pattern)-1] unit := pattern[len(pattern)-1] num, err := strconv.Atoi(numStr) if err != nil { return 0, fmt.Errorf("invalid number in pattern: %s", pattern) } switch unit { case 'd': return time.Duration(num) * 24 * time.Hour, nil case 'w': return time.Duration(num) * 7 * 24 * time.Hour, nil case 'm': // Approximate: 30 days return time.Duration(num) * 30 * 24 * time.Hour, nil case 'y': // Approximate: 365 days return time.Duration(num) * 365 * 24 * time.Hour, nil default: return 0, fmt.Errorf("unknown unit: %c (use d/w/m/y)", unit) } } // FormatRecurrenceDuration converts time.Duration back to "1w", "2d" format func FormatRecurrenceDuration(d time.Duration) string { days := int(d.Hours() / 24) if days%365 == 0 && days/365 > 0 { return fmt.Sprintf("%dy", days/365) } if days%30 == 0 && days/30 > 0 { return fmt.Sprintf("%dm", days/30) } if days%7 == 0 && days/7 > 0 { return fmt.Sprintf("%dw", days/7) } return fmt.Sprintf("%dd", days) } // CalculateNextDue calculates next due date based on current and recurrence func CalculateNextDue(currentDue time.Time, recurrence time.Duration) time.Time { return currentDue.Add(recurrence) } // SpawnNextInstance creates a new task instance from completed recurring task // This will be implemented after we have the CRUD operations func SpawnNextInstance(completedInstance *Task) error { if completedInstance.ParentUUID == nil { return fmt.Errorf("task is not a recurring instance") } // TODO: Implement after GetTask is available return fmt.Errorf("not implemented yet") }