#!/usr/bin/env perl
use LWP::Simple;
use JSON;
use utf8;
use warnings;
use constant debug => $ENV{DEBUG};
use App::gh;

$|++;

my $screen_width = 92;

sub _debug {
    print STDERR @_,"\n" if debug;
}

sub _info {
    print STDERR @_,"\n";
}

sub print_list {
    my @lines = @_;

    my $column_w = 0;

    map { 
        $column_w = length($_->[0]) if length($_->[0]) > $column_w ; 
    } @lines;

    for my $arg ( @lines ) {
        my $title = shift @$arg;

        my $padding = int($column_w) - length( $title );

        if ( $ENV{WRAP} && ( $column_w + 3 + length( join " ",@$arg) ) > $screen_width ) {
            # wrap description
            my $string = $title . " " x $padding . " - " . join(" ",@$arg) . "\n";
            $string =~ s/\n//g;

            my $cnt = 0;
            my $firstline = 1;
            my $tab = 4;
            my $wrapped = 0;
            while( $string =~ /(.)/g ) {
                $cnt++;

                my $c = $1;
                print $c;

                if( $c =~ /[ \,]/ && $firstline && $cnt > $screen_width ) {
                    print "\n" . " " x ($column_w + 3 + $tab );
                    $firstline = 0;
                    $cnt = 0;
                    $wrapped = 1;
                }
                elsif( $c =~ /[ \,]/ && ! $firstline && $cnt > ($screen_width - $column_w) ) {
                    print "\n" . " " x ($column_w + 3 + $tab );
                    $cnt = 0;
                    $wrapped = 1;
                }
            }
            print "\n";
            print "\n" if $wrapped;
        }
        else { print $title;
            print " " x $padding;
            print " - ";
            print join " " , @$arg;
            print "\n";
        }

    }
}



# my $config = parse_config $ENV{HOME} . "/.gitconfig";
# use Data::Dumper; warn Dumper( $config );

my $act = shift;
$SIG{INT} = sub {
    exit;
};

if( ! $act || $act eq 'help' ) 
{
    print <<'END';

App::gh

show help message;

    $ gh help

* list:

    list all repository of c9s:

        $ gh list c9s

    if you want text wrapped:

        $ WRAP=1 gh list c9s

* clone:

    clone Plack repository from miyagawa:

        $ gh clone miyagawa/Plack   # default: read-only 

    or:

        $ gh clone miyagawa Plack

        $ gh clone gugod Social http

        $ gh clone clkao Web-Hippie ro

    clone from read-only uri:

        $ gh clone miyagawa/Plack ro 

    clone from ssh uri:

        $ gh clone miyagawa/Plack ssh  

* search:

    search repository:

        $ gh search Plack

* cloneall:

    to clone all repository of miyagawa:

        $ gh cloneall miyagawa 

        $ gh cloneall clkao ro  # read-only

* fork;

    to fork project:

        $ gh fork clkao AnyMQ

    to fork current project:
        
        $ cd clkao/AnyMQ
        $ gh fork

* network:

    to show fork network:

        $ cd App-gh/
        $ gh network
            c9s/App-gh - watchers(4) forks(1)
          gugod/App-gh - watchers(1) forks(0)

* pull from other's fork:

    pull from gugod/project.git branch master (default):

        $ cd project
        $ gh pullfork gugod           

    pull from gugod/project.git branch feature:

        $ cd project
        $ gh pullfork gugod feature    

END
    exit;

}
elsif( $act eq 'search' || $act eq 's' ) {
    my $keyword = shift;
    my $json = get 'http://github.com/api/v2/json/repos/search/' . $keyword;

    my $result = decode_json( $json );

    my @ary = ();
    for my $repo ( @{ $result->{repositories} } ) {
        my $name = sprintf "%s/%s", $repo->{username} , $repo->{name};
        my $desc = $repo->{description};
        push @ary, [ $name , $desc ];
    }

    print_list @ary;
}
elsif( $act eq 'clone' || $act eq 'c' ) {
    my $user;
    my $repo;

    $user = shift;
    if( $user =~ /\// ) {
        ($user,$repo) = split /\//,$user;
    }
    else {
        $repo = shift;
    }

    my $attr = shift || 'ro';
    my $uri;
    if( $attr eq 'ro' ) {
        $uri = sprintf "git://github.com/%s/%s.git" , $user , $repo;
    }
    elsif( $attr eq 'ssh' ) {
        $uri = sprintf "git\@github.com:%s/%s.git" , $user , $repo;
    }
    print $uri . "\n";
    system( qq{git clone $uri} );
}



elsif( $act eq 'pullfork' || $act eq 'pf' ) 
{
    my $acc  = shift;
    my $branch = shift || 'master';

    die "git config not found." if  ! -e ".git/config" ;
    my $config = parse_config( ".git/config" );

    # git://github.com/miyagawa/Tatsumaki.git
    for my $remote ( values %{ $config->{remote} } ) {
        if ( $remote->{url} =~ m{git://github.com/(.*?)/(.*?).git} 
            || $remote->{url} =~ m{git\@github.com:(.*?)/(.*?).git} ) 
        {
            my ( $my, $repo ) = ( $1, $2 );
            my $uri = sprintf( qq(git://github.com/%s/%s.git) , $acc , $repo );
            qx(git pull $uri $branch);
            last;
        }
    }

}
elsif( $act eq 'list' ) 
{
    my $acc = shift;
    my $json = get 'http://github.com/api/v2/json/repos/show/' . $acc;
    my $data = decode_json( $json );
    my @lines = ();
    for my $repo ( @{ $data->{repositories} } ) {
        my $repo_name = $repo->{name};
        push @lines , [  
            $acc . "/" . $repo->{name} ,
            ($repo->{description}||"")
        ];
    }
    print_list @lines;
}
elsif( $act eq 'cloneall' || $act eq 'ca' ) {
    my $acc = shift;
    my $attr = shift || 'ro';

    my $json = get 'http://github.com/api/v2/json/repos/show/' . $acc;
    my $data = decode_json( $json );

    for my $repo ( @{ $data->{repositories} } ) {
        my $repo_name = $repo->{name};
        my $local_repo_name = $repo_name;
        $local_repo_name =~ s/\.git$//;

        my $uri;
        if( $attr eq 'ro' ) {
            $uri = sprintf "git://github.com/%s/%s.git" , $acc , $repo_name;
        }
        elsif( $attr eq 'ssh' ) {
            $uri = sprintf "git\@github.com:%s/%s.git" , $acc , $repo_name;
        }
        print $uri . "\n";

        if( -e $local_repo_name ) {
            print "Updating " . $local_repo_name . " ...\n";
            qx{ cd $local_repo_name ; git pull origin master };
        }
        else {
            print "Cloning " . $repo->{name} . " ...\n";
            qx{ git clone -q $uri };
        }
    }
}
elsif( $act eq 'network' ) {
    die "Git config not found." if ( ! -e ".git/config" );

    my $config = parse_config( ".git/config" );
    for my $remote ( values %{ $config->{remote} } ) {
        # git://github.com/miyagawa/Tatsumaki.git
        if ( $remote->{url} =~ m{git://github.com/(.*?)/(.*?).git} 
            || $remote->{url} =~ m{git\@github.com:(.*?)/(.*?).git} ) 
        {
            my ($acc,$repo) = ($1,$2);
            # curl http://github.com/api/v2/yaml/repos/show/schacon/ruby-git/network
            my $url = qq(http://github.com/api/v2/json/repos/show/$acc/$repo/network);
            my $json = get $url;
            my $objs = decode_json($json);
            # use Data::Dumper; warn Dumper( $objs );
            my $networks = $objs->{network};

            for my $net ( @$networks ) {
                _info sprintf( "% 17s - watchers(%d) forks(%d)"
                    , $net->{owner} . '/' . $net->{name}
                    , $net->{watchers}
                    , $net->{forks}
                    );
            }
            last;
        }
    }
}
elsif( $act eq 'fork' ) {
    my $user;
    my $repo;

    $user = shift;
    if( $user && $user =~ /\// ) {
        ($user,$repo) = split /\//,$user;
    }
    else {
        $repo = shift;
    }

    my $auth = get_github_auth();

    unless( $auth ) {
        die "Github authtoken not found. Can not fork repository.\n";
    }

    unless ( $repo ) {
        # detect .git directory
        if ( -e ".git/config" ) {
            my $config = parse_config( ".git/config" );
            for my $remote ( values %{ $config->{remote} } ) {
                # git://github.com/miyagawa/Tatsumaki.git
                if ( $remote->{url} 
                        =~ m{git://github.com/(.*?)/(.*?).git}  ) {
                        if( $1 && $2 ) {
                            ($user,$repo) = ( $1 , $2 );

                            _info "Found GitHub repository of $user/$repo";

                            my $remote_uri = qq( git\@github.com:@{[ $auth->{user} ]}/$repo.git);

                            _info "Adding remote '@{[ $auth->{user} ]}' => $remote_uri";

                            # url = git@github.com:c9s/App-gh.git
                            my $cmd = qq( git remote add @{[ $auth->{user} ]} $remote_uri);
                            _debug $cmd;
                            qx($cmd);

                            _info "Remote added.";
                        }
                }
            }
        }
    }

    # curl -F 'login=schacon' -F 'token=XXX' http://github.com/api/v2/yaml/repos/fork/dim/retrospectiva
=pod

$VAR1 = {
          'repository' => {
                            'has_downloads' => bless( do{\(my $o = 1)}, 'JSON::XS::Boolean' ),
                            'owner' => 'c9s',
                            'has_issues' => bless( do{\(my $o = 0)}, 'JSON::XS::Boolean' ),
                            'name' => 'AnyMQ',
                            'private' => $VAR1->{'repository'}{'has_issues'},
                            'has_wiki' => $VAR1->{'repository'}{'has_downloads'},
                            'pushed_at' => '2010/04/06 00:40:45 -0700',
                            'description' => 'Simple message queue based on AnyEvent',
                            'watchers' => 1,
                            'forks' => 0,
                            'homepage' => '',
                            'created_at' => '2010/07/21 06:08:11 -0700',
                            'fork' => $VAR1->{'repository'}{'has_downloads'},
                            'url' => 'http://github.com/c9s/AnyMQ',
                            'open_issues' => 0
                          }
        };
=cut

    _info "Forking...";

    my $uri = sprintf("http://github.com/api/v2/json/repos/fork/%s/%s?login=%s&token=%s", $user , $repo , $auth->{user} , $auth->{token} );
    my $json = get( $uri );
    my $data = decode_json( $json );

    use Data::Dumper; 
    warn Dumper( $data ) if debug;

    _info "Repository forked:";

    $data = $data->{repository};
    print "  Name:          " . $data->{name} . "\n";
    print "  Description:   " . $data->{description} . "\n";
    print "  Owner:         " . $data->{owner} . "\n";
    print "  Watchers:      " . $data->{watchers} . "\n";
    print "  Created at:    " . $data->{created_at} . "\n";
    print "  Pushed at:     " . $data->{pushed_at} . "\n";
    print "  Fork:          " . $data->{'fork'} . "\n";
    print "  URL:           " . $data->{url} . "\n";
    print "  Homepage:      " . $data->{homepage} . "\n";
}




