namespace ClaudeDo.Worker.State;

public interface ITaskStateService
{
    Task<TransitionResult> EnqueueAsync(string taskId, CancellationToken ct);
    Task<TransitionResult> StartRunningAsync(string taskId, DateTime startedAt, CancellationToken ct);
    Task<TransitionResult> CompleteAsync(string taskId, DateTime finishedAt, string? result, CancellationToken ct);
    Task<TransitionResult> SubmitForReviewAsync(string taskId, DateTime finishedAt, string? result, CancellationToken ct);
    Task<TransitionResult> SubmitInteractiveForReviewAsync(string taskId, DateTime finishedAt, CancellationToken ct);
    Task<TransitionResult> SubmitForChildrenAsync(string taskId, DateTime finishedAt, string? result, CancellationToken ct);
    Task<TransitionResult> FailAsync(
        string taskId, DateTime finishedAt, string? error, CancellationToken ct,
        string failureReason = "error", int? turnsUsed = null, int? maxTurns = null);
    Task<TransitionResult> CancelAsync(string taskId, DateTime finishedAt, CancellationToken ct, bool allowFromIdle = false);
    Task<TransitionResult> ResetToIdleAsync(string taskId, CancellationToken ct);

    Task<TransitionResult> ApproveReviewAsync(string taskId, CancellationToken ct);
    Task<TransitionResult> RejectToQueueAsync(string taskId, string feedback, CancellationToken ct);
    Task<TransitionResult> RejectToIdleAsync(string taskId, CancellationToken ct);
    Task<TransitionResult> ClearReviewFeedbackAsync(string taskId, CancellationToken ct);

    Task<TransitionResult> ForceSetStatusAsync(string taskId, ClaudeDo.Data.Models.TaskStatus status, CancellationToken ct);

    // Guarded "manual done toggle" affordance (task list checkbox): unlike ForceSetStatusAsync,
    // these check the expected starting status in the same ExecuteUpdateAsync filter so a
    // concurrent picker claim (Idle/Done -> Running) is not silently overwritten.
    Task<TransitionResult> MarkDoneAsync(string taskId, DateTime finishedAt, CancellationToken ct);
    Task<TransitionResult> UnmarkDoneAsync(string taskId, CancellationToken ct);

    // Guarded "remove from queue" affordance. Expects the task to still be Queued; clears
    // BlockedByTaskId in the same update so a queued chain child never ends up Idle-but-blocked.
    Task<TransitionResult> DequeueToIdleAsync(string taskId, CancellationToken ct);

    Task<TransitionResult> StartPlanningAsync(string parentId, CancellationToken ct);
    Task<TransitionResult> FinalizePlanningAsync(string parentId, CancellationToken ct);

    Task<TransitionResult> BlockOnAsync(string taskId, string predecessorTaskId, CancellationToken ct);
    Task<TransitionResult> UnblockAsync(string taskId, CancellationToken ct);

    // dependsOnTaskId null clears the dependency. Rejects self-reference, an unknown dependency
    // id, and a link that would create a cycle -- see TaskStateService for the walk.
    Task<TransitionResult> SetDependsOnAsync(string taskId, string? dependsOnTaskId, CancellationToken ct);

    // Surfaces a WaitingForChildren parent for review once all its children are terminal.
    // Best-effort (swallows and logs failures) — safe to call after any child mutation,
    // e.g. deleting the last non-terminal child (no terminal transition fires for a delete).
    Task TryAdvanceParentAsync(string parentId);

    Task<int> RecoverStaleRunningAsync(string reason, CancellationToken ct);
}
