The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package App::SD::Replica::redmine::PullEncoder;
use Any::Moose;
extends 'App::SD::ForeignReplica::PullEncoder';

# use YAML::XS qw(Dump);
use Params::Validate qw(:all);

has sync_source => (
    isa => 'App::SD::Replica::redmine',
    is  => 'rw',
    required => 1
);

sub ticket_id {
    my ($self, $ticket) = @_;
    return $ticket->id;
}

sub find_matching_tickets {
    my $self = shift;
    my %query = (@_);

    my $redmine = $self->sync_source->redmine;
    my $search = $redmine->search_ticket( $query{query} );

    my @results = $search->results;
    return \@results;
}

sub find_matching_transactions {
    my $self = shift;
    my %args = validate( @_, { ticket => 1, starting_transaction => 1 } );

    my @txns;
    my $raw_txn = $args{ticket}->histories;

    for my $txn (@$raw_txn) {
        push @txns, {
            timestamp => $txn->date->epoch,
            serial => $txn->id,
            object => $txn
        }
    }

    # if ($args{ticket}->id == 420) {
    #     die Dump({
    #         ticket_id => $args{ticket}->id,
    #         txn => [ map { { id => $_->{serial}, comment => $_->{comment} } } @txns ]
    #     });
    # }

    return \@txns;
}

sub translate_ticket_state {
    my $self         = shift;
    my $ticket       = shift;
    my $transactions = shift;

    my $final_state = {
        $self->sync_source->uuid . '-id' => $ticket->id,
        status      => lc($ticket->status),
        summary     => $ticket->subject,
        description => $ticket->description,
        priority    => $ticket->priority,
        created     => $ticket->created_at->ymd . " " . $ticket->created_at->hms,
        creator     => $ticket->author->email
    };
    my $initial_state = {%$final_state};

    for my $txn ( sort { $b->{'serial'} <=> $a->{'serial'} } @$transactions ) {
        $txn->{post_state} = { %$final_state };

        if ($txn->{serial} == 0) {
            $txn->{pre_state} = {};
            last;
        }

        my $property_changes = $txn->{object}->property_changes;
        while (my ($name, $changes) = each(%$property_changes)) {
            $initial_state->{$name} = $changes->{from};
        }

        $txn->{pre_state} = {%$initial_state};
    }

    return $initial_state, $final_state;
}

sub transcode_one_txn {
    my $self               = shift;
    my $txn_wrapper        = shift;
    my $older_ticket_state = shift;
    my $newer_ticket_state = shift;

    my $txn = $txn_wrapper->{object};

    if ($txn_wrapper->{serial} == 0) {
        return $self->transcode_create_txn($txn_wrapper, $older_ticket_state, $newer_ticket_state);
    }

    my $ticket_id   = $newer_ticket_state->{ $self->sync_source->uuid . '-id' };
    my $ticket_uuid = $self->sync_source->uuid_for_remote_id($ticket_id);
    my $creator     = $newer_ticket_state->{creator};
    my $created     = $newer_ticket_state->{created};

    my $changeset = Prophet::ChangeSet->new({
        original_source_uuid => $ticket_uuid,
        original_sequence_no => $txn->id,
        creator              => $creator,
        created              => $created,
    });

    my $change = Prophet::Change->new({
        record_type => 'ticket',
        record_uuid => $ticket_uuid,
        change_type => 'update_file',
    });

    for my $prop ( keys %{ $txn_wrapper->{post_state} } ) {
        my $new = $txn_wrapper->{post_state}->{$prop};
        my $old = $txn_wrapper->{pre_state}->{$prop};

        next unless defined($new) && defined($old);

        $change->add_prop_change(
            name => $prop,
            new  => $new,
            old  => $old,
        ) unless $new eq $old;
    }

    $changeset->add_change({ change => $change });

    $self->_include_change_comment($changeset, $ticket_uuid, $txn);
    return $changeset;
}

sub _include_change_comment {
    my $self        = shift;
    my $changeset   = shift;
    my $ticket_uuid = shift;
    my $txn         = shift;

    my $comment = $self->new_comment_creation_change();

    my $content = $txn->note || "";

    if ( $content !~ /^\s*$/s ) {
        $comment->add_prop_change(
            name => 'created',
            new  => $txn->date->ymd . ' ' . $txn->date->hms,
        );
        $comment->add_prop_change(
            name => 'creator',
            new => 'ccc@example.com',
        );
        $comment->add_prop_change( name => 'content', new => $content );
        $comment->add_prop_change(
            name => 'content_type',
            new  => 'text/plain',
        );
        $comment->add_prop_change( name => 'ticket', new => $ticket_uuid, );

        $changeset->add_change( { change => $comment } );
    }
}

sub transcode_create_txn {
    my $self        = shift;
    my $txn         = shift;
    my $create_data = shift;
    my $final_data  = shift;

    my $ticket_id   = $final_data->{ $self->sync_source->uuid . '-id' };
    my $ticket_uuid = $self->sync_source->uuid_for_remote_id($ticket_id);
    my $creator     = 'xxx@example.com';
    my $created     = $final_data->{created};

    my $changeset = Prophet::ChangeSet->new({
        original_source_uuid => $ticket_uuid,
        original_sequence_no => 0,
        creator              => $creator,
        created              => $created,
    });

    my $change = Prophet::Change->new({
        record_type => 'ticket',
        record_uuid => $ticket_uuid,
        change_type => 'add_file',
    });

    while ( my ($name, $value) = each %{ $txn->{post_state} }) {
        $change->add_prop_change(
            name => $name,
            new => $value
        )
    }

    $changeset->add_change({ change => $change });

    # for my $att ( @{ $txn->{object}->attachments } ) {
    #     $self->_recode_attachment_create(
    #         ticket_uuid => $ticket_uuid,
    #         txn         => $txn->{object},
    #         changeset   => $changeset,
    #         attachment  => $att,
    #     );
    # }

    return $changeset;
}

sub translate_prop_status {}

sub resolve_user_id_to {
    my $self = shift;
    my $to   = shift;
    my $id   = shift;
    return $id;
}


__PACKAGE__->meta->make_immutable;
no Any::Moose;
1;