# ABSTRACT: Change a task's status

package App::karr::Cmd::Move;
our $VERSION = '0.401';
use Moo;
use MooX::Cmd;
use MooX::Options (
  usage_string => 'USAGE: karr move ID[,ID,...] STATUS [--claim NAME] [--next|--prev]',
);
use App::karr::Role::BoardAccess;
use App::karr::Role::Output;
use App::karr::Task;
use App::karr::Config;
use Time::Piece;

with 'App::karr::Role::BoardAccess', 'App::karr::Role::Output';


option next => (
  is => 'ro',
  doc => 'Advance to next status',
);

option prev => (
  is => 'ro',
  doc => 'Move to previous status',
);

option claim => (
  is => 'ro',
  format => 's',
  doc => 'Claim task for an agent',
);

sub execute {
  my ($self, $args_ref, $chain_ref) = @_;

  $self->check_positional_args($args_ref, 2);

  $self->sync_before;

  my @pos = $self->positional_args($args_ref);
  my $id_str = $pos[0] or die "Usage: karr move ID[,ID,...] [STATUS]\n";
  my @ids = $self->parse_ids($id_str);
  my $new_status = $pos[1];

  my $ec = $self->store->effective_config;
  my @statuses = $self->store->all_status_names;

  my @results;
  for my $id (@ids) {
    my $task = $self->find_task($id);
    die "Task $id not found\n" unless $task;

    my $task_new_status = $new_status;

    if ($self->next) {
      my $idx = $self->_status_index(\@statuses, $task->status);
      die "Already at last status\n" if $idx >= $#statuses;
      $task_new_status = $statuses[$idx + 1];
    } elsif ($self->prev) {
      my $idx = $self->_status_index(\@statuses, $task->status);
      die "Already at first status\n" if $idx <= 0;
      $task_new_status = $statuses[$idx - 1];
    }

    die "New status required\n" unless $task_new_status;

    # Check require_claim
    if ($self->store->status_requires_claim($task_new_status) && !$self->claim && !$task->has_claimed_by) {
      die "Status '$task_new_status' requires --claim\n";
    }

    if ($self->claim) {
      $task->claimed_by($self->claim);
      $task->claimed_at(gmtime->datetime . 'Z');
    }

    my $old_status = $task->status;
    $task->status($task_new_status);

    # Set started/completed timestamps
    if ($task_new_status eq 'in-progress' && !$task->has_started) {
      $task->started(gmtime->strftime('%Y-%m-%d'));
    }
    if ($task_new_status eq 'done' && !$task->has_completed) {
      $task->completed(gmtime->strftime('%Y-%m-%d'));
    }

    $self->save_task($task);

    push @results, { id => $task->id, title => $task->title, old_status => $old_status, new_status => $task_new_status };
    printf "Moved task %d: %s -> %s\n", $task->id, $old_status, $task_new_status unless $self->json;
  }

  $self->sync_after;

  $self->print_json_results(@results);
}

sub _status_index {
  my ($self, $statuses, $status) = @_;
  for my $i (0..$#$statuses) {
    return $i if $statuses->[$i] eq $status;
  }
  die "Unknown status: $status\n";
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

App::karr::Cmd::Move - Change a task's status

=head1 VERSION

version 0.401

=head1 SYNOPSIS

    karr move 7 done
    karr move 7 --next
    karr move 7,8,9 in-progress --claim agent-fox

=head1 DESCRIPTION

Moves one or more tasks to a new status. The command understands explicit
target statuses and relative movement via C<--next> or C<--prev>, and it
enforces C<require_claim> when the destination status requires an owner.

=head1 OPTIONS

=over 4

=item * C<--next>, C<--prev>

Advance or rewind relative to the status order defined in the board config.

=item * C<--claim>

Claim the task while moving it. This is commonly used for
C<in-progress> or C<review> states.

=back

=head1 SEE ALSO

L<karr>, L<App::karr>, L<App::karr::Cmd::Show>, L<App::karr::Cmd::Edit>,
L<App::karr::Cmd::Pick>, L<App::karr::Cmd::Handoff>

=head1 SUPPORT

=head2 Issues

Please report bugs and feature requests on GitHub at
L<https://github.com/Getty/karr/issues>.

=head2 IRC

Join C<#langertha> on C<irc.perl.org> or message Getty directly.

=head1 CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

=head1 AUTHOR

Torsten Raudssus <getty@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> L<https://raudssus.de/>.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
