package Newslash::Plugin::Sendmail;
use Mojo::Base 'Mojolicious::Plugin';
use Email::Valid;
use Email::Simple;
use Email::Sender::Simple;
use Email::Sender::Transport::SMTP;
use Encode;
use Data::Dumper;

has 'last_error';
has 'app';

sub register {
    my ($self, $app, $conf) = @_;
    $self->app($app);
    $app->helper(sendmail => sub { shift; $self->sendmail(@_); });

    # default config values
    my $cnf = $app->config->{Sendmail} ||= {};

    $cnf->{default_from} ||= 'admin@example.com';
    $cnf->{smtp_host} ||= 'example.com';
    $cnf->{smtp_port} ||= '25';
}

sub _encode_header {
    my ($self, $text) = @_;
    my $encoded = encode('MIME-Header-ISO_2022_JP', $text);
    $encoded =~ s/\n//g;
    return $encoded;
}

sub _send {
    my ($self, $from, $to, $title, $body) = @_;

    # create header and body
    my $header = [
                  From    => $self->_encode_header($from),
                  To      => $self->_encode_header($to),
                  Subject => $self->_encode_header($title),
                  'Content-Type' => 'text/plain; charset=ISO-2022-JP',
                  'Content-Transfer-Encoding' => '7bit',
                 ];

    my $encoded_body = encode('iso-2022-jp', $body);

    # create message
    my $email = Email::Simple->create(header => $header,
                                      body => $encoded_body);

    # create transport
    my $smtp_host = $self->app->config->{Sendmail}->{smtp_host};
    my $smtp_port = $self->app->config->{Sendmail}->{smtp_port};
    my $smtp_timeout = $self->app->config->{Sendmail}->{smtp_timeout};
    my $transport = Email::Sender::Transport::SMTP->new({ host => $smtp_host,
                                                          port => $smtp_port,
                                                          timeout => $smtp_timeout,
                                                        });

    # send message
    my $rs = eval { Email::Sender::Simple->send($email, {transport => $transport}) };
    if (!$rs) {
        my ($msg, $code) = ($@->message, $@->code);
        $self->app->log->error("Sendmail: sendmail error. $msg ($code)");
        return;
    }
    return 1;
}

sub _render {
    my ($self, $template_name, $vars, $opts) = @_;
    $opts ||= {};

    my $renderer = $self->app->tt2renderer;
    my $rs = $renderer->render($template_name, $vars);

    my ($title, $body) = split(/\n/, $rs, 2);
    $body =~ s/\A\n+//;
    return ($title, $body);
}

sub sendmail {
    my $self = shift;
    my $args = {@_};

    if (!defined $args->{to}) {
        $self->app->log->error("Sendmail: no recipient given!");
        return;
    }

    my $to_address;
    my $recipient_user;

    # check recipient
    if (ref($args->{to}) eq "HASH") {
        $recipient_user = $args->{to};
    }
    elsif (ref($args->{to}) eq "ARRAY") {
        # TODO
    }
    elsif (ref($args->{to}) eq "") {
        if ($args->{to} =~ m/^\d+$/) {
            # uid is given
            $recipient_user = $self->app->model('users')->select(uid => $args->{to});
        }
        else {
            my $encoded_to = encode('MIME-Header-ISO_2022_JP', $args->{to});
            if (Email::Valid->address($encoded_to)) {
                $to_address = $args->{to};
            }
        }
    }

    if ($recipient_user) {
        $to_address = $recipient_user->{realemail};
    }

    if (!$to_address) {
        $self->app->log->error("Sendmail: invalid recipient: $args->{to}");
        return;
    }


    # check from address
    my $from_address = $args->{from} || $self->app->config->{Sendmail}->{default_from};

    # create title and body
    my $title = $args->{title};
    my $body = $args->{body};

    if ($args->{template}) {
        # render template
        ($title, $body) = eval { $self->_render($args->{template},
                                                   $args->{params}); };
        if (!$title) {
            $self->app->log->error("Sendmail: template error: $@");
            return;
        }
    }

    if (!$title) {
        $self->app->log->error("Sendmail: no title given. to: $to_address");
        return;
    }

    if (!$body) {
        $self->app->log->error("Sendmail: no body given. title: $title, to: $to_address");
        return;
    }

    # if render only mode, return items.
    if ($args->{render_only}) {
        return wantarray ? ($from_address, $to_address, $title, $body) : { from => $from_address,
                                                                             to => $to_address,
                                                                             title => $title,
                                                                             body => $body };
    }

    # send
    my $rs = $self->_send($from_address, $to_address, $title, $body);

    if (!$rs) {
        $self->app->log->error("Sendmail: fail to send mail. title: $title, to: $to_address");
        return;
    }

    return 1;
}

1;

=encoding utf8

=head1 NAME

Newslash::Plugin::Sendmail - Newslash sendmail plugin

=head1 SYNOPSIS

  # Mojolicious
  $app->plugin('Newslash::Plugin::Sendmail');

=head1 DESCRIPTION

L<Newslash::Plugin::Sendmail> implements mail related tasks.


=head1 HELPERS

L<Mojolicious::Plugin::Sendmail> implements the following helpers.

=head2 boxes

  [% helpers.boxes() %]

Fetch box contents for current user and returns them.

=head2 format_timestamp

  $c->format_timestamp(user => $user, epoch => $epoch, format => "user")
  $c->format_timestamp(datetime => $dt, format => "simple")

Return formated string.

=head1 METHODS

=head2 register

  $plugin->register(Mojolicious->new);

Register helpers in L<Mojolicious> application.

head2 sendmail

  $app->sendmail(to => $user,
                 template => "message/initial_password",
                 params => $render_params);

Render template with params and send mail.

=head1 SEE ALSO

L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.

=cut
