package Slovo::Task::SendPasswEmail;
use Mojo::Base 'Slovo::Task::SendOnboardingEmail', -signatures;

use Mojo::Util qw(b64_encode encode sha1_sum);
use Mojo::File 'path';
use Mojo::Collection 'c';
my $CONF = {};

# Sends a message for login with temporary password to $to_user and returns the
# generated token. The token will be deleted by
# _delete_passw_token($job,$token).
my sub _mail_message ($t, $to_user, $app, $domain) {
  state $mt        = Mojo::Template->new(vars => 1);
  state $mail_body = 'task/send_passw_email.txt.ep';
  state $mail_tmpl
    = c(@{$app->renderer->paths})->first(sub { -f path($_, $mail_body)->to_string; })
    . "/$mail_body";

  #This token will be compared with the one provided by the user.
  my $token = sha1_sum($t . encode('UTF-8' => $to_user->{id}));
  my $body  = $mt->render_file(
    $mail_tmpl => {
      time            => $t,
      to_user         => $to_user,
      domain          => $domain,
      token           => $token,
      token_valid_for => $CONF->{token_valid_for},
    });
  my $subject
    = 'Временен ключ за вход за '
    . $to_user->{first_name} . ' '
    . $to_user->{last_name} . ' в '
    . $domain;
  my $message = <<"MAIL";
To: $to_user->{email}
From: $CONF->{'Net::SMTP'}{mail}
Subject: =?UTF-8?B?${\ b64_encode(encode('UTF-8', $subject), '') }?=
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
Message-Id: <acc-msg-to-$to_user->{login_name}$t\@$domain>
Date: ${\ Mojo::Date->new->to_datetime }
MIME-Version: 1.0

${\ encode('UTF-8', $body)}

MAIL

  $app->debug('Message to be send:' . $/ . $message);
  Slovo::Task::SendOnboardingEmail::send_mail_by_net_smtp($message, $to_user, $app);
  return $token;
}

my sub _mail_passw_login ($job, $to_user, $domain) {
  state $app = $job->app;
  my $t         = time;
  my $token     = _mail_message($t, $to_user, $app, $domain);
  my $token_row = {
    to_uid     => $to_user->{id},
    token      => $token,
    start_date => $t,
    stop_date  => $t + $CONF->{token_valid_for}};
  $app->dbx->db->insert('passw_login' => $token_row);
  $app->minion->enqueue(
    delete_passw_login => [$to_user->{id}, $token] => {delay => $CONF->{token_valid_for}}
  );
  return $job->finish('Писмото с временен ключ за влизане в '
      . $domain . ' до '
      . $to_user->{first_name} . ' '
      . $to_user->{last_name}
      . ' бе успешно изпратено!');

}

my sub _delete_passw_login ($job, $uid, $token) {
  state $app = $job->app;
  $app->dbx->db->delete('passw_login' => {token => $token, to_uid => $uid});

  # also delete expired but not deleted (for any reason) login tokens.
  $app->dbx->db->delete('passw_login' => {stop_date => {'<' => time}});
  return $job->finish;
}


sub register ($self, $app, $conf) {
  $CONF = $self->validate_conf($conf);
  $app->minion->add_task(mail_passw_login   => \&_mail_passw_login);
  $app->minion->add_task(delete_passw_login => \&_delete_passw_login);
  return $self;
}

1;

=encoding utf8

=head1 NAME

Slovo::Task::SendPasswEmail - sends email to user containing one time password.

=head1 SYNOPSIS

  # common configuration for similar Tasks in slovo.conf
  my $mail_cfg = {
    token_valid_for => 24 * 3600,
    'Net::SMTP'     => {
      new => {
        Host => 'mail.example.org',

        #Debug          => 1,
        SSL             => 1,
        SSL_version     => 'TLSv1',
        SSL_verify_mode => 0,
        Timeout         => 60,
             },
      auth => ['slovo@example.org', 'Pa55w03D'],
      mail => 'slovo@example.org',
    },
  };

  #load the plugin via slovo.conf
  plugins => [
    #...
    #Tasks
    {'Task::SendOnboardingEmail' => $mail_cfg},
    {'Task::SendPasswEmail'      => $mail_cfg},
  ],

=head1 DESCRIPTION

Slovo::Task::SendPasswEmail extends L<Slovo::Task::SendOnboardingEmail>. This
is poor design, but quick and working solution for now. It implements tasks for
sending email for forgotten password and for deleting the temporary password.



=head1 METHODS

The following methods are implemented.

=head2 register

Reads the configuration and adds the implemented tasks to L<Minion>.

=head1 TASKS

The following tasks are implemented.

=head2 mail_passw_login

Sends an email containing one time password to users who claim they forgot
their password.  It uses
L<Slovo::Task::SendOnboardingEmail/send_mail_by_net_smtp> to send the mail. The
taks is invoked by action L<Slovo::Controller::Auth/lost_password_form>

Arguments: C<$job, $to_user, $domain>.

C<job> is the job object provided by L<Minion>. C<$to_user> is a hash reference
containing the user properties found in a C<users> table record. C<$domain> is
the current domain.

  my $job_id = $c->minion->enqueue(
                     mail_passw_login => [$user, $c->req->headers->host]);

=head2 delete_passw_login

Arguments: C<$job, $uid, $token>.

Invoked by L</mail_passw_login>. Deletes the temporary password after delay
C<$CONF-E<gt>{token_valid_for}>.

  $app->minion->enqueue(delete_passw_login => [$to_user->{id}, $token] =>
                        {delay => $CONF->{token_valid_for}});

=head1 SEE ALSO

L<Slovo::Controller::Auth>, L<Slovo::Task::SendOnboardingEmail>.

=cut