#!/usr/bin/env perl6
use v6;
use lib './lib';
use Net::IRC::Bot;
use Text::Emotion::Scorer;

class Emotive::UserScore {
    has %user_scores;
    has $emotion = Text::Emotion::Scorer.new;
    has %ignore; #= ('') X=> 1;
    has %admin = <AdminUser> X=> 1;

    method log ($event) {
        my $log = open "emobot.log", :a or $event.msg("Couldn't open the log sorry!");
        if $log {
            #Timestamp this log
            $log.say(now);
            for %user_scores.keys.sort -> $user {
                $log.say("$user\t%user_scores{$user}{'score'}\t%user_scores{$user}{'num'}\t%user_scores{$user}{'sum'}");
            }
            close $log;
            $event.msg("I logged the dataz.");
        }
    }
    
    multi method ignore () {
        return %ignore.keys.join(" ");
    }

    multi method ignore ($user,$state) {
        if $state {
            %ignore{$user} = 1;
        } else {
            %ignore.delete($user);
        }
    }

    multi method score ($user) {
        if %user_scores{$user}:exists {
            return %user_scores{$user}{'score'};
        } else {
            return 0;
        }
    }

    multi method score ($user, $score) {
        if $score == 0.0 {
            return;
        }
        if %user_scores{$user}:exists {
            %user_scores{$user}{'num'}++;
            %user_scores{$user}{'sum'} += $score;
            %user_scores{$user}{'score'} = %user_scores{$user}{'sum'} / %user_scores{$user}{'num'};
        } else {
            %user_scores{$user} = { 'score' => +($score), 'sum' => +($score), 'num' => 1 };
        }
    }

    method command (Net::IRC::Event $event, $user, $message) {
        my ($command, @args) = $message.split(/\s/);
        
        #Find the most positive user on average
        if $command eq '@hero' {
            my $hero = %user_scores.keys.grep({%user_scores{$_}{'score'} > 0.0}).sort({%user_scores{$^a}{'score'} <=> %user_scores{$^b}{'score'}}).list.pop;
            if $hero {
                $event.msg("$hero is the most awesome hero, with an emo score of %user_scores{$hero}{'score'}! YAY! >:3");
            } else {
                $event.msg("There are no heroes who can save this channel.");
            }
        }

        #Find the most negitive user on average
        if $command eq '@villain' {
            my $villain = %user_scores.keys.grep({%user_scores{$_}{'score'} < 0.0}).sort({%user_scores{$^a}{'score'} <=> %user_scores{$^b}{'score'}}).list.shift;
            if $villain {
                $event.msg("$villain is the most dasterdly villain, with an emo score of %user_scores{$villain}{'score'}! BOO! HISS! :<");
            } else {
                $event.msg("Yay, there are no villains on this channel! WIN! >:D");
            }
        }

        #Output the current score average on the user
        if $command eq '@emo' {
            my ($person) = @args;
            if $person {
                $event.msg("$user: $person" ~ "'s emo = " ~ self.score($person));
            } else {
                $event.msg("$user: Your emo = " ~ self.score($user));
            }
        }

        #Let the bot admin kill the bot
        if $command eq '@die' {
            exit if %admin{$user}:exists;
        }
        
        #Let the bot admin kill the bot
        if $command eq '@log' {
            if %admin{$user}:exists {
                self.log($event);
            }
        }

        #Allow users to remove thier own data being held by the bot
        if $command eq '@forget' {
            my ($person) = @args;
            $person = $user unless $person;
            if ($user ~~ /^^$person/) {
                if %user_scores{$person}:exists {
                    %user_scores.delete($person);
                    $event.msg("Who is $person I forgot... ;)");
                } else {
                    $event.msg("I didn't know anything about $person anyway!");
                }
            } else {
                $event.msg("Sorry $user only $person can make me forget.");
            }
        }
        
        #Allow users to opt out
        if $command eq '@ignore' {
            my ($person) = @args;
            if $person {
                if $user eq $person {
                    self.ignore($user,True);
                    $event.msg("I will ignore $user.");
                } else {
                    $event.msg("Sorry $user only $person can make me ignore them.");
                }
            } else {
                $event.msg("Ignoring: "~self.ignore);
            }
        }

        #Allow users to opt back in
        if $command eq '@listen' {
            my ($person) = @args;
            $person = $user unless $person;
            if $user eq $person {
                self.ignore($user,False);
                $event.msg("$user I'm here for you and always listening.");
            } else {
                $event.msg("Sorry $user only $person can make me listen to them.");
            }
        }

    }

    multi method said ($event where {.what ~~ /^^<[@]>/ or .who<nick> !~~ %ignore}) {
        my Str $message = ~$event.what;
        my Str $user = ~$event.who<nick>;

        #Handle commands

        if $message ~~ /^^<[@]>/ {
            self.command($event,$user,$message);
        } else {
            #Otherwise score and save
            my $score = +($emotion.score($message));
            if $score <= -7.0 and self.score($user) > 0.0 {
                $event.msg("$user sounds more negative than usual, give them a big hug!");
            }
            $event.msg("Negativity level $score detected, WARNING!") if $score <= -10;
            self.score($user,$score);
        }
    }
}

sub MAIN(:$server="localhost",:$port=6667,:$channel="#bot",:$nick="emobot",Bool :$debug=False) {
    my $stuff = Text::Emotion::Scorer.new();
    Net::IRC::Bot.new(
	    nick       => $nick,
    	server     => $server,
        port       => $port,
    	channels   => $channel,
        #altnicks   => $nick Z~ ("_","__",^10),
        #username   => 'emobot',
    	modules    => (Emotive::UserScore.new()),
    	debug      => $debug
    ).run;
}

sub USAGE {
    say "emobot --server=<server> --channel=<channel> --nick=<nick>";
}
