#!/bin/perl

#
# TODO: detect existing repos and automatically modify config file accordingly
# TODO: function to detect unclean working trees
# TODO: Handle cloning
# TODO: Handle pulling
# TODO: Trigger hooks on clone/pull
#

print("This shit ain't done yet!\n");
# exit;

use strict;
use warnings;
use feature ("signatures");
use YAML();
use JSON();
use WWW::Curl::Easy;
use WWW::Curl::Multi;
use Data::Dump();
use File::Path();

use constant USERAGENT =>
  "User-Agent: MarxBot/4.2.0 (A script reading some information about repos)";

my @handles;
my %conf;
my $active_repos    = 0;
my $active_requests = 0;

sub set_curl( $handle, $url, @headers ) {
    $handles[$handle]{curl} = WWW::Curl::Easy->new;
    $handles[$handle]{curl}->setopt( CURLOPT_URL, $url );
    $handles[$handle]{curl}->pushopt( CURLOPT_HTTPHEADER, [USERAGENT] );
    for my $header (@headers) {
        $handles[$handle]{curl}->pushopt( CURLOPT_HTTPHEADER, [$header] );
    }
    $handles[$handle]{curl}->setopt( CURLOPT_PRIVATE, $handle );
    $handles[$handle]{curl}
      ->setopt( CURLOPT_WRITEDATA, \$handles[$handle]{memory} );
}

sub add_callback( $handle, $callback ) {
    push( @{ $handles[$handle]{callbacks} }, $callback );
}

sub exec_multicurl() {
    my $curlm = WWW::Curl::Multi->new;
    for my $handle (@handles) {
        if ($handle) {
            $curlm->add_handle( $handle->{curl} );
            $active_requests++;
        }
    }
    while ($active_requests) {
        my $active_transfers = $curlm->perform;
        if ( $active_transfers != $active_requests ) {
            while ( my ( $handle, $return_value ) = $curlm->info_read ) {
                if ($handle) {
                    $active_requests--;
                    if ( $handles[$handle]{callbacks} ) {
                        for my $callback ( @{ $handles[$handle]->{callbacks} } )
                        {
                            $callback->($handle);
                        }
                    }
                    delete $handles[$handle];
                }
            }
        }
    }
}

sub json_decode($handle) {
    $handles[$handle]{memory} = JSON::decode_json( $handles[$handle]{memory} );
}

sub filter($handle) {
    my @tmp;
    my $plugin = $conf{plugins}[ $handles[$handle]->{plugin} ];
    foreach my $repo ( @{ $handles[$handle]{memory} } ) {
        if ( $repo->{ssh_url} ) {
            push( @tmp, $repo->{ %$plugin{url_type} } );
        }
    }
    $handles[$handle]{memory} = \@tmp;
}

sub process_urls($handle) {
    my @tmp;
    foreach my $url ( @{ $handles[$handle]{memory} } ) {
        my %repo;
        if ( $url =~
            /^(.*[\/:](([a-zA-Z0-9-_.]+)\/([a-zA-Z0-9-_.]+?))(?:\.git)?\/?)$/ )
        {
            $repo{url}  = $1;
            $repo{name} = $2;
        }
        else {
            return;
        }
        continue if grep /^$repo{name}$/, $conf{block_repos};
        my $path;
        foreach my $directory ( @{ $conf{directories} } ) {
            foreach my $reponame ( @{ %$directory{repos} } ) {
                if ( $reponame =~ $repo{name} ) {
                    $path = %$directory{path};
                    last;
                }
            }
        }
        if ( !$path and !$conf{block_unsorted} ) {
            $path = "\${XDG_DOCUMENTS_DIR}/unsorted_repos";
            $repo{path} = `printf $path`;
            push( @tmp, %repo );
        }
    }
    $handles[$handle]{memory} = \@tmp;
}

sub dump($handle) {
    print("------ Handle $handle ------\n");
    Data::Dump::dump( $handles[$handle]{memory} );
}

# sub handle_repos($handle) {
#     foreach my $repo (@{$handles[$handle]->{memory}}) {
#         if (-d $repo{})
#     }
# }

sub read_conf() {
    my $configdir;
    if ( $ENV{XDG_CONFIG_HOME} ) {
        $configdir = "$ENV{XDG_CONFIG_HOME}/clonedev";
    }
    else {
        $configdir = "$ENV{HOME}/.config/clonedev";
    }
    open( my $cfg, '<', $configdir . "/config.yml" ) or die;
    my ( $hashref, $arrayref, $string ) = YAML::Load( do { local $/; <$cfg> } );
    close($cfg);
    %conf = %$hashref;
}

# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
# ░  ░░░░  ░░░      ░░░        ░░   ░░░  ░
# ▒   ▒▒   ▒▒  ▒▒▒▒  ▒▒▒▒▒  ▒▒▒▒▒    ▒▒  ▒
# ▓        ▓▓  ▓▓▓▓  ▓▓▓▓▓  ▓▓▓▓▓  ▓  ▓  ▓
# █  █  █  ██        █████  █████  ██    █
# █  ████  ██  ████  ██        ██  ███   █
# ████████████████████████████████████████


read_conf();

# $last_handle++;
# set_curl( $last_handle, "https://api.github.com/octocat" );
# add_callback(
#     $last_handle,
#     sub ($handle) {
#         print( $handles[$handle]{memory} );
#     }
# );
#
my $last_handle = 0;
foreach my $i ( keys @{ $conf{plugins} } ) {
    my %plugin = %{ $conf{plugins}[$i] };
    chomp(
        $ENV{TOKEN} =
          $plugin{token_cmd}
        ? `$plugin{token_cmd}`
        : ""
    );
    foreach ( @{ $plugin{extra_headers} } ) {
        last if ( !$_ );
        $_ = `printf "$_"`;
    }
    foreach my $j ( keys @{ $plugin{targets} } ) {
        $last_handle++;
        $handles[$last_handle]{plugin} = $i;
        print("$plugin{api_url}/$plugin{targets}[$j]/$plugin{endpoint}\n");
        set_curl( $last_handle, "$plugin{api_url}/$plugin{targets}[$j]/$plugin{endpoint}",
            $plugin{extra_headers} );
        add_callback( $last_handle, \&dump );
        add_callback( $last_handle, \&json_decode );
        add_callback( $last_handle, \&filter );
        add_callback( $last_handle, \&process_urls );
        add_callback( $last_handle, \&dump );
    }
}

exec_multicurl();