// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package lunatask

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
)

// TaskStatus represents the workflow state of a task.
//
//nolint:recvcheck // MarshalJSON must use value receiver, UnmarshalJSON must use pointer
type TaskStatus string

// Valid task status values.
const (
	// StatusLater is the default status for new tasks.
	StatusLater      TaskStatus = "later"
	StatusNext       TaskStatus = "next"
	StatusInProgress TaskStatus = "in-progress"
	StatusWaiting    TaskStatus = "waiting"
	StatusCompleted  TaskStatus = "completed"
)

// Errors returned by TaskStatus operations.
var (
	// ErrInvalidTaskStatus is returned when parsing an unknown task status string.
	ErrInvalidTaskStatus = errors.New("invalid task status")
)

// String returns the task status value as a string.
func (s TaskStatus) String() string {
	return string(s)
}

// MarshalJSON implements [json.Marshaler].
// Translates "in-progress" to "started" for the API.
func (s TaskStatus) MarshalJSON() ([]byte, error) {
	val := string(s)
	if s == StatusInProgress {
		val = "started"
	}

	data, err := json.Marshal(val)
	if err != nil {
		return nil, fmt.Errorf("marshaling task status: %w", err)
	}

	return data, nil
}

// UnmarshalJSON implements [json.Unmarshaler].
// Translates "started" from the API to "in-progress".
func (s *TaskStatus) UnmarshalJSON(data []byte) error {
	var val string
	if err := json.Unmarshal(data, &val); err != nil {
		return fmt.Errorf("task status must be a string: %w", err)
	}

	if val == "started" {
		*s = StatusInProgress

		return nil
	}

	*s = TaskStatus(val)

	return nil
}

// AllTaskStatuses returns all valid task status values in workflow order.
func AllTaskStatuses() []TaskStatus {
	return []TaskStatus{
		StatusLater,
		StatusNext,
		StatusInProgress,
		StatusWaiting,
		StatusCompleted,
	}
}

// ParseTaskStatus parses a string to a TaskStatus value (case-insensitive).
// Valid values: "later", "next", "in-progress", "waiting", "completed".
func ParseTaskStatus(str string) (TaskStatus, error) {
	switch strings.ToLower(str) {
	case "later":
		return StatusLater, nil
	case "next":
		return StatusNext, nil
	case "in-progress":
		return StatusInProgress, nil
	case "waiting":
		return StatusWaiting, nil
	case "completed":
		return StatusCompleted, nil
	default:
		return "", fmt.Errorf("%w: %q", ErrInvalidTaskStatus, str)
	}
}
