# Common hooks library
package Devscripts::Salsa::Hooks;

use strict;
use Devscripts::Output;
use Moo::Role;
use Switch;

sub add_hooks {
    my ($self, $repo_id, $repo) = @_;
    if (   $self->config->kgb
        or $self->config->disable_kgb
        or $self->config->tagpending
        or $self->config->disable_tagpending
        or $self->config->irker
        or $self->config->disable_irker
        or $self->config->email
        or $self->config->disable_email) {
        my $hooks = $self->enabled_hooks($repo_id);
        return 1 unless (defined $hooks);
        # KGB hook (IRC)
        if ($self->config->kgb or $self->config->disable_kgb) {
            unless ($self->config->irc_channel->[0]
                or $self->config->disable_kgb) {
                ds_warn "--kgb needs --irc-channel";
                return 1;
            }
            if ($self->config->irc_channel->[1]) {
                ds_warn "KGB accepts only one --irc-channel value,";
            }
            if ($hooks->{kgb}) {
                ds_warn "Deleting old kgb (was $hooks->{kgb}->{url})";
                $self->api->delete_project_hook($repo_id, $hooks->{kgb}->{id});
            }
            if ($self->config->irc_channel->[0]
                and not $self->config->disable_kgb) {
                # TODO: if useful, add parameters for this options
                eval {
                    $self->api->create_project_hook(
                        $repo_id,
                        {
                            url => $self->config->kgb_server_url
                              . $self->config->irc_channel->[0],
                            map { ($_ => 1) } @{ $self->config->kgb_options },
                        });
                    ds_verbose "KGB hook added to project $repo_id (channel: "
                      . $self->config->irc_channel->[0] . ')';
                };
                if ($@) {
                    ds_warn "Fail to add KGB hook: $@";
                    if (!$self->config->no_fail) {
                        return 1;
                    }
                }
            }
        }
        # Irker hook (IRC)
        if ($self->config->irker or $self->config->disable_irker) {
            unless ($self->config->irc_channel->[0]
                or $self->config->disable_irker) {
                ds_warn "--irker needs --irc-channel";
                return 1;
            }
            if ($hooks->{irker}) {
                no warnings;
                ds_warn
"Deleting old irker (redirected to $hooks->{irker}->{recipients})";
                $self->api->delete_project_service($repo_id, 'irker');
            }
            if ($self->config->irc_channel->[0]
                and not $self->config->disable_irker) {
                # TODO: if useful, add parameters for this options
                my $ch = join(' ',
                    map { '#' . $_ } @{ $self->config->irc_channel });
                $self->api->edit_project_service(
                    $repo_id, 'irker',
                    {
                        active      => 1,
                        server_host => $self->config->irker_host,
                        (
                            $self->config->irker_port
                            ? (server_port => $self->config->irker_port)
                            : ()
                        ),
                        default_irc_uri   => $self->config->irker_server_url,
                        recipients        => $ch,
                        colorize_messages => 1,
                    });
                ds_verbose
                  "Irker hook added to project $repo_id (channel: $ch)";
            }
        }
        # email on push
        if ($self->config->email or $self->config->disable_email) {
            if ($hooks->{email}) {
                no warnings;
                ds_warn
"Deleting old email-on-push (redirected to $hooks->{email}->{recipients})";
                $self->api->delete_project_service($repo_id, 'emails-on-push');
            }
            if (@{ $self->config->email_recipient }
                and not $self->config->disable_email) {
                # TODO: if useful, add parameters for this options
                $self->api->edit_project_service(
                    $repo_id,
                    'emails-on-push',
                    {
                        recipients => join(' ',
                            map { my $a = $_; $a =~ s/%p/$repo/; $a }
                              @{ $self->config->email_recipient }),
                    });
                no warnings;
                ds_verbose
                  "Email-on-push hook added to project $repo_id (recipients: "
                  . join(' ', @{ $self->config->email_recipient }) . ')';
            }
        }
        # Tagpending hook
        if ($self->config->tagpending or $self->config->disable_tagpending) {
            if ($hooks->{tagpending}) {
                ds_warn
                  "Deleting old tagpending (was $hooks->{tagpending}->{url})";
                $self->api->delete_project_hook($repo_id,
                    $hooks->{tagpending}->{id});
            }
            my $repo_name = $self->api->project($repo_id)->{name};
            unless ($self->config->disable_tagpending) {
                eval {
                    $self->api->create_project_hook(
                        $repo_id,
                        {
                            url => $self->config->tagpending_server_url
                              . $repo_name,
                            push_events => 1,
                        });
                    ds_verbose "Tagpending hook added to project $repo_id";
                };
                if ($@) {
                    ds_warn "Fail to add Tagpending hook: $@";
                    if (!$self->config->no_fail) {
                        return 1;
                    }
                }
            }
        }
    }
    return 0;
}

sub enabled_hooks {
    my ($self, $repo_id) = @_;
    my $hooks;
    my $res = {};
    if (   $self->config->kgb
        or $self->config->disable_kgb
        or $self->config->tagpending
        or $self->config->disable_tagpending) {
        $hooks = eval { $self->api->project_hooks($repo_id) };
        if ($@) {
            ds_warn "Unable to check hooks for project $repo_id";
            return undef;
        }
        foreach my $h (@{$hooks}) {
            $res->{kgb} = {
                id      => $h->{id},
                url     => $h->{url},
                options => [grep { $h->{$_} and $h->{$_} eq 1 } keys %$h],
              }
              if $h->{url} =~ /\Q$self->{config}->{kgb_server_url}\E/;
            $res->{tagpending} = {
                id  => $h->{id},
                url => $h->{url},
              }
              if $h->{url} =~ /\Q$self->{config}->{tagpending_server_url}\E/;
        }
    }
    if (    ($self->config->email or $self->config->disable_email)
        and $_ = $self->api->project_service($repo_id, 'emails-on-push')
        and $_->{active}) {
        $res->{email} = $_->{properties};
    }
    if (    ($self->config->irker or $self->config->disable_irker)
        and $_ = $self->api->project_service($repo_id, 'irker')
        and $_->{active}) {
        $res->{irker} = $_->{properties};
    }
    return $res;
}

sub desc {
    my ($self, $repo) = @_;
    my @res = ();
    if ($self->config->desc) {
        my $str = $self->config->desc_pattern;
        $str  =~ s/%P/$repo/g;
        $repo =~ s#.*/##;
        $str  =~ s/%p/$repo/g;
        push @res, description => $str;
    }
    if ($self->config->build_timeout) {
        push @res, build_timeout => $self->config->build_timeout;
    }
    if ($self->config->issues) {
        switch ($self->config->issues) {
            case "private" { push @res, issues_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, issues_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, issues_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_ISSUES";
            }
        }
    }
    if ($self->config->repo) {
        switch ($self->config->repo) {
            case "private" { push @res, repository_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, repository_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, repository_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_REPO";
            }
        }
    }
    if ($self->config->mr) {
        switch ($self->config->mr) {
            case "private" {
                push @res, merge_requests_access_level => "private";
            }
            case qr/y(es)?|true|enabled?/ {
                push @res, merge_requests_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, merge_requests_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_MR";
            }
        }
    }

    if ($self->config->forks) {
        switch ($self->config->forks) {
            case "private" { push @res, forking_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, forking_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, forking_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_FORKS";
            }
        }
    }
    if ($self->config->lfs) {
        switch ($self->config->lfs) {
            case qr/y(es)?|true|enabled?/ {
                push @res, lfs_enabled => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, lfs_enabled => "disabled";
            } else {
                print "error with SALSA_ENABLE_LFS";
            }
        }
    }
    if ($self->config->packages) {
        switch ($self->config->packages) {
            case qr/y(es)?|true|enabled?/ {
                push @res, packages_enabled => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, packages_enabled => "disabled";
            } else {
                print "error with SALSA_ENABLE_PACKAGES";
            }
        }
    }
    if ($self->config->jobs) {
        switch ($self->config->jobs) {
            case "private" { push @res, builds_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, builds_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, builds_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_JOBS";
            }
        }
    }
    if ($self->config->container) {
        switch ($self->config->container) {
            case "private" {
                push @res, container_registry_access_level => "private";
            }
            case qr/y(es)?|true|enabled?/ {
                push @res, container_registry_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, container_registry_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_CONTAINER";
            }
        }
    }
    if ($self->config->analytics) {
        switch ($self->config->analytics) {
            case "private" { push @res, analytics_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, analytics_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, analytics_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_ANALYTICS";
            }
        }
    }
    if ($self->config->requirements) {
        switch ($self->config->requirements) {
            case "private" {
                push @res, requirements_access_level => "private";
            }
            case qr/y(es)?|true|enabled?/ {
                push @res, requirements_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, requirements_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_REQUIREMENTS";
            }
        }
    }
    if ($self->config->wiki) {
        switch ($self->config->wiki) {
            case "private" { push @res, wiki_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, wiki_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, wiki_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_WIKI";
            }
        }
    }
    if ($self->config->snippets) {
        switch ($self->config->snippets) {
            case "private" { push @res, snippets_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, snippets_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, snippets_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_SNIPPETS";
            }
        }
    }
    if ($self->config->pages) {
        switch ($self->config->pages) {
            case "private" { push @res, pages_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, pages_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, pages_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_PAGES";
            }
        }
    }
    if ($self->config->releases) {
        switch ($self->config->releases) {
            case "private" { push @res, releases_access_level => "private"; }
            case qr/y(es)?|true|enabled?/ {
                push @res, releases_access_level => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, releases_access_level => "disabled";
            } else {
                print "error with SALSA_ENABLE_RELEASES";
            }
        }
    }
    if ($self->config->auto_devops) {
        switch ($self->config->auto_devops) {
            case qr/y(es)?|true|enabled?/ {
                push @res, auto_devops_enabled => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, auto_devops_enabled => "disabled";
            } else {
                print "error with SALSA_ENABLE_AUTO_DEVOPS";
            }
        }
    }
    if ($self->config->request_acc) {
        switch ($self->config->request_acc) {
            case qr/y(es)?|true|enabled?/ {
                push @res, request_access_enabled => "enabled";
            }
            case qr/no?|false|disabled?/ {
                push @res, request_access_enabled => "disabled";
            } else {
                print "error with SALSA_ENABLE_REQUEST_ACC";
            }
        }
    }
    if ($self->config->disable_remove_branch) {
        push @res, remove_source_branch_after_merge => 0;
    } elsif ($self->config->enable_remove_branch) {
        push @res, remove_source_branch_after_merge => 1;
    }
    if ($self->config->ci_config_path) {
        push @res, ci_config_path => $self->config->ci_config_path;
    }
    if ($self->config->request_access) {
        if ($self->config->request_access =~ qr/y(es)?|true|enabled?|1/) {
            push @res, request_access_enabled => 1;
        } else {
            push @res, request_access_enabled => 0;
        }
    }
    return @res;
}

sub desc_multipart {
    my ($self, $repo) = @_;
    my @res = ();
    if ($self->config->avatar_path) {
        my $str = $self->config->avatar_path;
        $str =~ s/%p/$repo/g;
        unless (-r $str) {
            if (!$self->config->no_fail) {
                ds_error("Unable to find: $str");
                exit 1;
            }
            ds_warn "Unable to find: $str";
        } else {
            # avatar_path (salsa) -> avatar (GitLab API)
            push @res, avatar => $str;
        }
    }
    return @res;
}

1;
