use strict;
use warnings;
use Path::Tiny;
use JSON::XS; # JSON parser module
use DDP;
use v5.36;
use DateTime::Format::ISO8601;
use Try::Catch;
use Getopt::Long;
use Image::MetaData::JPEG;
use File::stat;

GetOptions(
    "pull-versions" => \my $get_versions,
    "restore"       => \my $do_restores,
    "verbose"       => \my $verbose,
    "print"         => \my $print,
    "copy"          => \my $copy,
    "overwrite"     => \my $overwrite,
    "folder=s"      => \my $folder_name,
    "update-ts"     => \my $update_ts,
    "since"         => \my $since,
    "match"         => \my $match,
) or die("Error in command line arguments\n");


$match = '.*' unless $match;
my %restores;

my %stats = (
    exists   => 0,
    restored => 0,
    failed   => 0,
    selected => 0,
);

my %folders = (
    'koku_downloads'  => {
        'id'   => 'm7ko5-adoga',
        'path' => '/mnt/nasty/koku_downloads',
    },
    'koku_documents'  => {
        'id'   => 'krvxc-ajsfv',
        'path' => '/mnt/nasty/Koku',
    },
    'koku_desktop'    => {
        'id'   => 'vhimk-o3gwx',
        'path' => '/mnt/nasty/koku_desktop',
    },
    'shared_pictures' => {
        'id'   => 'p6jqq-nouth',
        'path' => '/mnt/nasty/Media/Pictures'
    },
    'koku_music'      => {
        'id'   => 'mdhgr-gd7rv',
        'path' => '/mnt/nasty/Media/Music/Natalia'
    },
    'project-conquer' => {
        'id'   => 'qypth-g6xkb',
        'path' => '/mnt/nasty/project-conquer'
    },
    'highpoint'       => {
        'id'   => 'jekig-3yzvw',
        'path' => '/mnt/nasty/highpoint'
    },
);

my $folder_id = $folders{$folder_name}{'id'};
my $target_dir = $folders{$folder_name}{'path'};
my $source_dir = $folders{$folder_name}{'path'} . "/.stversions";
my $version_data = "$folder_name.json";

sub get_versions() {
    my $curl = qq{curl -k -X GET -H "X-API-KEY: oemTvSg94cShmEymeuct66GRsyutLTGg" https://dri.tz:8090/rest/folder/versions?folder=$folder_id > $folder_name.json};
    system($curl);
    say $curl;
}

sub get_json() {
    my $json_file = path($version_data);
    my $decoded_json;
    if (-e $json_file) {
        my $json_data = $json_file->slurp;
        $decoded_json = decode_json($json_data);
    }
    else {
        die "JSON file not found at $json_file";
    }
    return $decoded_json;
};

sub generate_restores($path, $version_date, $version_time, $restore_path) {
    if ($restores{$path}) {
        say "Path exists, checking for latest verson" if $verbose;
        if ($version_date > $restores{$path}{'version_time'}) {
            say "Later version found" if $verbose;
            $restores{$path} = {
                'version_date' => $version_date,
                'version_time' => $version_time,
                'restore_path' => $restore_path,
            };
        }
        else {
            say "Keeping current version" if $verbose;
        }
    }
    else {
        say "Inserting new path" if $verbose;
        $restores{$path} = {
            'version_date' => $version_date,
            'version_time' => $version_time,
            'restore_path' => $restore_path,
        };
    }

}

sub restore_versions() {
    for my $path (sort keys %restores) {
        my $source = path("$source_dir/" . $restores{$path}{'restore_path'});
        my $dest = path("$target_dir/$path");
        say "Source:  $source" if $verbose;
        say "Dest: $dest" if $verbose;
        my $res;

        unless (-d $dest->parent) {
            $dest->parent->mkdir;
        }

        if (! -f $dest || $overwrite) {
            try {
                $res = 'restored';
                # my $restore_copy = $source->copy($dest) if $copy;  # Doesn't preserve timestamps
                my $restore_copy = system('cp', '-p', $source, $dest) if $copy;
                say "$restore_copy successfully restored" if $verbose;
                ++$stats{'restored'};
            }
            catch {
                $res = 'failed  ';
                say "$source -> $dest failed to restore" if $verbose;
                ++$stats{'failed'};
            }
        }
        else {
            $res = 'exists  ';
            ++$stats{'exists'};
        }

        if ($update_ts) {
            update_timestamp($path);
            say "updated timestamp" if $verbose;
        }

        my $processed = $stats{'restored'} + $stats{'exists'} + $stats{'failed'};
        my $selected = $stats{'selected'};
        say sprintf('%.2f', $processed * 100 / $selected) . "% $processed/$selected $res\t$dest" if $print;
    }
}

sub check_restores() {
    my $decoded_json = get_json();
    foreach my $path (sort keys %$decoded_json) {
        for my $version (@{$decoded_json->{$path}}) {
            my $ts = DateTime::Format::ISO8601->parse_datetime($version->{'versionTime'});
            if ($ts->ymd != '2023-08-25') {
                say $path
            }
}

sub update_timestamp($path) {
    # return unless $path =~ /\.jpe?g$/i;
    try {
        my $source = path("$source_dir/" . $restores{$path}{'restore_path'});
        my $dest = path("$target_dir/$path");
        my $stat = stat($source);
        utime($stat->atime, $stat->mtime, $dest);
    }
    catch {
        say "unable to update timestamp";
    }
}


get_versions() if $get_versions;
do_restores() if $do_restores;

