#!/usr/bin/env perl

use Digest::SHA qw(sha256_hex);
use JSON;
use POSIX qw(strftime);
use Time::Piece;

my $LINK = "1~{0}       /~{0}   tilde.club      70";

sub compare_gophermaps {
   my ($user, $cache) = @_;

   my $user_path = "/home/$user/public_gopher/gophermap";
   my $current_time = time;
   my $time_threshold = 259200;

   if (! -e $user_path) {
       # Ignore user if public_gopher folder is not found
       return;
   }

   if (exists $cache->{$user} && $current_time - $cache->{$user} < $time_threshold) {
       print $LINK =~ s/{0}/$user/r;
       return;
   }

   my $skel_path = "/etc/skel/public_gopher/gophermap";
   open my $skel_fh, '<', $skel_path or die "Unable to open file: $!";
   my $skel_hash = sha256_hex(do { local $/; <$skel_fh> });
   close $skel_fh;

   eval {
       open my $user_fh, '<', $user_path or die "Unable to open file: $!";
       my $user_hash = sha256_hex(do { local $/; <$user_fh> });
       close $user_fh;

       if ($user_hash ne $skel_hash) {
           $cache->{$user} = $current_time;
           print $LINK =~ s/{0}/$user/r;
       } else {
           delete $cache->{$user} if exists $cache->{$user};
       }
   } or do {
       # Ignore exceptions and treat the gophermap file as one to not list
       delete $cache->{$user} if exists $cache->{$user};
   };
}

sub main {
   my $cache_path = "cache.json";

   # Load the cache from disk if it exists, otherwise create a new cache
   my $cache = (-e $cache_path) ? decode_json(do { local $/; open my $fh, '<', $cache_path or die "Unable to open file: $!"; <$fh> }) : {};

   opendir my $home_dir, '/home' or die "Unable to open directory: $!";
   foreach my $user (sort { lc $a cmp lc $b } readdir $home_dir) {
       compare_gophermaps($user, $cache);
   }
   closedir $home_dir;

   # Save the cache to disk
   open my $cache_fh, '>', $cache_path or die "Unable to open file: $!";
   print $cache_fh to_json($cache);
   close $cache_fh;
}