package Devscripts::Uscan::git;

use strict;
use Cwd qw/abs_path/;
use Devscripts::Uscan::Output;
use Devscripts::Uscan::Utils;
use Devscripts::Uscan::_vcs;
use Dpkg::IPC;
use File::Path 'remove_tree';
use Moo::Role;

######################################################
# search $newfile $newversion (git mode/versionless)
######################################################
sub git_search {
    my ($self) = @_;
    my ($newfile, $newversion);
    if ($self->versionless) {
        $newfile = $self->parse_result->{filepattern}; # HEAD or heads/<branch>
        if ($self->pretty eq 'describe') {
            $self->gitmode('full');
        }
        if (    $self->gitmode eq 'shallow'
            and $self->parse_result->{filepattern} eq 'HEAD') {
            uscan_exec(
                'git',
                'clone',
                '--quiet',
                '--bare',
                '--depth=1',
                $self->parse_result->{base},
                "$self->{downloader}->{destdir}/" . $self->gitrepo_dir
            );
            $self->downloader->gitrepo_state(1);
        } elsif ($self->gitmode eq 'shallow'
            and $self->parse_result->{filepattern} ne 'HEAD')
        {    # heads/<branch>
            $newfile =~ s&^heads/&&;    # Set to <branch>
            uscan_exec(
                'git',
                'clone',
                '--quiet',
                '--bare',
                '--depth=1',
                '-b',
                "$newfile",
                $self->parse_result->{base},
                "$self->{downloader}->{destdir}/" . $self->gitrepo_dir
            );
            $self->downloader->gitrepo_state(1);
        } else {
            uscan_exec(
                'git', 'clone', '--quiet', '--bare',
                $self->parse_result->{base},
                "$self->{downloader}->{destdir}/" . $self->gitrepo_dir
            );
            $self->downloader->gitrepo_state(2);
        }
        if ($self->pretty eq 'describe') {

            # use unannotated tags to be on safe side
            spawn(
                exec => [
                    'git',
"--git-dir=$self->{downloader}->{destdir}/$self->{gitrepo_dir}",
                    'describe',
                    '--tags'
                ],
                wait_child => 1,
                to_string  => \$newversion
            );
            $newversion =~ s/-/./g;
            chomp($newversion);
            if (
                mangle(
                    $self->watchfile,  \$self->line,
                    'uversionmangle:', \@{ $self->uversionmangle },
                    \$newversion
                )
            ) {
                return undef;
            }
        } else {
            my $tmp = $ENV{TZ};
            $ENV{TZ} = 'UTC';
            $newfile
              = $self->parse_result->{filepattern};    # HEAD or heads/<branch>
            if ($self->parse_result->{filepattern} eq 'HEAD') {
                spawn(
                    exec => [
                        'git',
"--git-dir=$self->{downloader}->{destdir}/$self->{gitrepo_dir}",
                        'log',
                        '-1',
                        "--date=format-local:$self->{date}",
                        "--pretty=$self->{pretty}"
                    ],
                    wait_child => 1,
                    to_string  => \$newversion
                );
            } else {
                $newfile =~ s&^heads/&&;    # Set to <branch>
                spawn(
                    exec => [
                        'git',
"--git-dir=$self->{downloader}->{destdir}/$self->{gitrepo_dir}",
                        'log',
                        '-1',
                        '-b',
                        "$newfile",
                        "--date=format-local:$self->{date}",
                        "--pretty=$self->{pretty}"
                    ],
                    wait_child => 1,
                    to_string  => \$newversion
                );
            }
            $ENV{TZ} = $tmp;
            chomp($newversion);
        }
    }
    ################################################
    # search $newfile $newversion (git mode w/tag)
    ################################################
    elsif ($self->mode eq 'git') {
        my @args = ('ls-remote', $self->parse_result->{base});
        # Try to use local upstream branch if available
        if (-d '.git') {
            my $out;
            eval {
                spawn(
                    exec       => ['git', 'remote', '--verbose', 'show'],
                    wait_child => 1,
                    to_string  => \$out
                );
            };
            # Check if git repo found in debian/watch exists in
            # `git remote show` output
            if ($out and $out =~ /^(\S+)\s+\Q$self->{parse_result}->{base}\E/m)
            {
                $self->downloader->git_upstream($1);
                uscan_warn
                  "Using $self->{downloader}->{git_upstream} remote origin";
                # Found, launch a "fetch" to be up to date
                spawn(
                    exec => ['git', 'fetch', $self->downloader->git_upstream],
                    wait_child => 1
                );
                @args = ('show-ref');
            }
        }
        ($newversion, $newfile)
          = get_refs($self, ['git', @args], qr/^\S+\s+([^\^\{\}]+)$/, 'git');
        return undef if !defined $newversion;
    }
    return ($newversion, $newfile);
}

sub git_upstream_url {
    my ($self) = @_;
    my $upstream_url
      = $self->parse_result->{base} . ' ' . $self->search_result->{newfile};
    return $upstream_url;
}

*git_newfile_base = \&Devscripts::Uscan::_vcs::_vcs_newfile_base;

sub git_clean {
    my ($self) = @_;

    # If git cloned repo exists and not --debug ($verbose=2) -> remove it
    if (    $self->downloader->gitrepo_state > 0
        and $verbose < 2
        and !$self->downloader->git_upstream) {
        my $err;
        uscan_verbose "Removing git repo ($self->{downloader}->{destdir}/"
          . $self->gitrepo_dir . ")";
        remove_tree "$self->{downloader}->{destdir}/" . $self->gitrepo_dir,
          { error => \$err };
        if (@$err) {
            local $, = "\n\t";
            uscan_warn "Errors during git repo clean:\n\t@$err";
        }
        $self->downloader->gitrepo_state(0);
    } else {
        uscan_debug "Keep git repo ($self->{downloader}->{destdir}/"
          . $self->gitrepo_dir . ")";
    }
    return 0;
}

1;
