#!/usr/bin/perl

=pod

=encoding UTF-8

=cut

# common modules
use strict;
use warnings FATAL => 'all';
use feature 'say';
use utf8;
use open qw(:std :utf8);

use DDP;
use Carp;
use Moment;
use Yandex::StarTrek;
use YAML qw(LoadFile);
use HTTP::Tiny;
use JSON::PP;
use Moment;
use Sort::Naturally qw(nsort);


# Захардкоженая дата чтобы ограничить выборку из стартрека
# (когда скрипт начент выдавать очень много данных, нужно будет
# увеличить эту дату)
my $START_DATE = '2016-12-01';


our %TICKETS;
our %TICKETS_COMMENTS;
our %TICKETS_CONDUCTOR;

=head2 get_conductor_create_time

Считаем что то что возвращает эта саба — это время выкладки.

На самом деле — это время создания тикета. Настоящее время выкладки —
это время создания плюс неколько минут (обычно около двух минут).

=cut

sub get_conductor_create_time {
    my ($conductor_ticket_id) = @_;

    my $response = HTTP::Tiny->new()->get(
        'https://c.yandex-team.ru/api/generator/markov.ticket?ticket=' . $conductor_ticket_id
    );

    my $data = decode_json $response->{content};

    return $data->{created_at};
}

sub get_stable_versions {
    my %stable_versions;

    my $output = `apt-cache policy yandex-partners`;
    $output =~ s/.*Version table:\n//ms;

    my $version;
    my $is_in_version = 0;

    foreach my $line (split /\n/, $output) {
        if ($line =~ /(2\.18\.\d+)/) {
            $version = $1;
            $is_in_version = 1;
        } else {
            $is_in_version = 0;
        }

        if (not $is_in_version) {
            if ($line =~ /stable/) {
                $stable_versions{$version} = 1
            }
        }
    }


    return %stable_versions;
}

sub smart_sort {
    my ($one, $two) = @_;

    my ($one_build) = $one->{build_ticket_summary} =~ /Сборка (\d+)./;
    my ($two_build) = $two->{build_ticket_summary} =~ /Сборка (\d+)./;

    return
        $one->{deployed_date_time} cmp $two->{deployed_date_time}
        || $one_build <=> $two_build
        ;
}

sub get_startrek {
    return Yandex::StarTrek->new(
        oauth_token => LoadFile('/etc/yastartrek.yaml')->{token},
    );
}

sub get_tickets_from_startrek {
    my ($start_date) = @_;

    my $tickets = get_startrek()->search_all(
        query => "Queue: PI and type: Release and Created: >= $start_date",
    );

    return $tickets;
}

sub get_ticket {
    my ($id) = @_;

    if (not $TICKETS{$id}) {
        $TICKETS{$id} = get_startrek()->get_issue($id);
    }

    return $TICKETS{$id};
}

sub get_ticket_comments {
    my ($id) = @_;

    if (not $TICKETS_COMMENTS{$id}) {
        $TICKETS_COMMENTS{$id} = get_startrek()->get_comments($id);
    }

    return $TICKETS_COMMENTS{$id};
}

sub get_last_conductor_id_from_ticket_comments {
    my ($ticket_id) = @_;

    if (not defined $TICKETS_CONDUCTOR{$ticket_id}) {
        my $comments = get_ticket_comments($ticket_id);

        foreach my $comment (reverse @{$comments}) {
            if ($comment->{text} =~ m'https://c\.yandex-team\.ru/tickets/(\d+)') {
                $TICKETS_CONDUCTOR{$ticket_id} = $1;
                last;
            }
        }

        $TICKETS_CONDUCTOR{$ticket_id} = '' if not $TICKETS_CONDUCTOR{$ticket_id};
    }

    return $TICKETS_CONDUCTOR{$ticket_id};
}

sub get_status_resolution {
    my ($status, $resolution) = @_;


    my $text = $status // '';

    if ($resolution) {
        $text .= ' / ' . $resolution;
    }

    return $text;
}

sub main {

    # Подготовка данных
    my $builds = [];

    my $release_tickets = get_tickets_from_startrek( $START_DATE );
    my %stable_versions = get_stable_versions();

    foreach my $ticket (@{$release_tickets}) {
        if (($ticket->{summary} // '')=~ /Сборка (\d+)./) {

            my $build_id = $1;
            my $full_build_id = "2.18.$build_id";

            my $release_ticket_id = $ticket->{parent}->{key};
            my $relese_ticket = get_ticket($release_ticket_id);
            my $conductor_id = get_last_conductor_id_from_ticket_comments($release_ticket_id);

            push @{$builds}, {
                build_id => $build_id,
                full_build_id => $full_build_id,

                conductor_id => $conductor_id,
                deployed_to_production => $stable_versions{ $full_build_id } ? 1 : 0,

                # это поле есть даже у сборок которые не были выложены
                # у тех сборок которые не были выложены это поле означает дата-время той сборки которая была выложена
                deployed_date_time => get_conductor_create_time($conductor_id),

                build_ticket_id => $ticket->{key},
                build_ticket_summary => $ticket->{summary} // '',
                build_ticket_status => $ticket->{status}->{key},
                build_ticket_resolution => $ticket->{resolution}->{key},
                build_ticket_assignee => $ticket->{assignee}->{id} // '',

                release_ticket_id => $release_ticket_id,
                release_ticket_summary => $relese_ticket->{summary} // '',
                release_ticket_status => $relese_ticket->{status}->{key},
                release_ticket_resolution => $relese_ticket->{resolution}->{key},
                release_ticket_assignee => $relese_ticket->{assignee}->{id} // '',
            }
        }
    }

    my $releases_without_build = [];

    foreach my $ticket (@{$release_tickets}) {
        if (
                not (grep { $ticket->{key} eq $_->{release_ticket_id} } @{$builds})
                && not (grep { $ticket->{key} eq $_->{build_ticket_id} } @{$builds})
            ) {
            push @{$releases_without_build}, $ticket->{key};
        }
    }

    # Вывод данных

    my $release_ticket_id = '';

    my $format = "%-45s %-18s %-37s %-23s %-20s";

    foreach my $build_data (sort { smart_sort($a, $b)} @{$builds}) {

        if ($release_ticket_id ne $build_data->{release_ticket_id}) {
            say sprintf $format,
                '',
                'st/' . $build_data->{release_ticket_id},
                $build_data->{release_ticket_summary},
                get_status_resolution($build_data->{release_ticket_status}, $build_data->{release_ticket_resolution}),
                $build_data->{release_ticket_assignee},
                ;
            $release_ticket_id = $build_data->{release_ticket_id};
        }

        say sprintf $format ,
            $build_data->{deployed_to_production}
                ? 'Выкладка в прод ' . $build_data->{deployed_date_time}
                : '',
            '  st/' . $build_data->{build_ticket_id},
            $build_data->{build_ticket_summary},
            get_status_resolution($build_data->{build_ticket_status}, $build_data->{build_ticket_resolution}),
            $build_data->{build_ticket_assignee},
            ;
    }

    foreach my $id (nsort @{$releases_without_build}) {
        my $ticket = get_ticket($id);

        say sprintf $format,
            '',
            'st/' . ($ticket->{key} // ''),
            ($ticket->{summary} // ''),
            get_status_resolution($ticket->{status}->{key}, $ticket->{resolution}->{key}),
            ($ticket->{assignee}->{id} // ''),
            ;
    }

}

main();
__END__
