package taskboard

import (
	"strings"
)

const InvalidTaskStatusTransitionCode = "invalid_task_status_transition"

type TaskStatusTransitionErrorDetails struct {
	CurrentStatus       Status   `json:"currentStatus"`
	DesiredStatus       Status   `json:"desiredStatus"`
	AllowedNextStatuses []Status `json:"allowedNextStatuses"`
	Hint                string   `json:"hint,omitempty"`
}

type InvalidTaskStatusTransitionError struct {
	Message             string
	CurrentStatus       Status
	DesiredStatus       Status
	AllowedNextStatuses []Status
	Hint                string
}

func (err InvalidTaskStatusTransitionError) Error() string {
	message := strings.TrimSpace(err.Message)
	if message == "" {
		return "invalid task status transition"
	}
	return message
}

func (err InvalidTaskStatusTransitionError) Unwrap() error {
	return ErrConflict
}

func (err InvalidTaskStatusTransitionError) Details() TaskStatusTransitionErrorDetails {
	return TaskStatusTransitionErrorDetails{
		CurrentStatus:       err.CurrentStatus,
		DesiredStatus:       err.DesiredStatus,
		AllowedNextStatuses: append([]Status(nil), err.AllowedNextStatuses...),
		Hint:                err.Hint,
	}
}

func validateKnownStatus(status Status) error {
	switch status {
	case StatusTodo, StatusInProgress, StatusInReview, StatusDone:
		return nil
	default:
		return badRequest("invalid task status")
	}
}

func validateStatusTransition(current Status, desired Status) error {
	if err := validateKnownStatus(desired); err != nil {
		return err
	}
	switch current {
	case StatusTodo, StatusInProgress, StatusInReview, StatusDone:
		return nil
	default:
		return invalidTaskStatusTransition(current, desired)
	}
}

func invalidTaskStatusTransition(current Status, desired Status) error {
	return invalidTaskStatusTransitionWithMessage("invalid task status transition", current, desired)
}

func invalidTaskStatusTransitionWithMessage(message string, current Status, desired Status) error {
	return InvalidTaskStatusTransitionError{
		Message:             message,
		CurrentStatus:       current,
		DesiredStatus:       desired,
		AllowedNextStatuses: allowedNextStatusesForStatus(current),
		Hint:                taskStatusTransitionHint(current),
	}
}

func allowedNextStatusesForStatus(current Status) []Status {
	statuses := []Status{StatusTodo, StatusInProgress, StatusInReview, StatusDone}
	next := make([]Status, 0, len(statuses)-1)
	for _, status := range statuses {
		if status != current {
			next = append(next, status)
		}
	}
	return next
}

func taskStatusTransitionHint(current Status) string {
	switch current {
	case StatusTodo, StatusInProgress, StatusInReview, StatusDone:
		return "Task status changes are open by default; configure status policy gates separately when needed."
	default:
		return "Refresh the task and retry with a valid status transition."
	}
}
