package Tweet::ToDelicious;

use v5.14;
use utf8;
use warnings;
use Getopt::Long;
use Net::Delicious;
use AnyEvent;
use AnyEvent::Twitter::Stream;
use AnyEvent::HTTP;
use Coro;
use Coro::LWP;
use Coro::AnyEvent;
use Log::Minimal;
use Tweet::ToDelicious::Entity;
use Sub::Retry;

our $VERSION = '0.08';

sub new {
    my $class = shift;
    my $cfg   = shift;
    my $self  = bless { config => $cfg }, $class;
    return $self;
}

sub run {
    my $self = shift;

    local $|                      = 1;
    local $Log::Minimal::AUTODUMP = 1;

    my $myname   = $self->{config}->{t2delicious}->{twitter_screen_name};
    my $cv       = AE::cv;
    my ($connector, $connect, $stream, $listener);

    $listener = sub {
        AnyEvent::Twitter::Stream->new(
            %{ $self->{config}->{twitter} },
            method     => 'userstream',
            on_connect => sub {
                undef $connector;
                infof( 'Start watching twitter:@%s, delicious:%s',
                    $myname, $self->{config}->{delicious}->{user} );
            },
            on_event => sub {
                my $tweet = shift;
                my $entry = Tweet::ToDelicious::Entity->new($tweet);
                if ( $entry->is_favorite && $entry->screen_name ~~ $myname ) {
                    my @posts = $entry->posts;
                    $self->_posts(@posts);
                }
            },
            on_tweet => sub {
                my $tweet = shift;
                my $entry = Tweet::ToDelicious::Entity->new($tweet);
                if (   ( $entry->screen_name ~~ $myname )
                    or ( $entry->in_reply_to_screen_name ~~ $myname ) )
                {
                    my @posts = $entry->posts;
                    $self->_posts(@posts);
                }
            },
            on_keepalive => sub {
                debugf("ping received");
            },
            on_eof => sub {
                debugf("eof received");
                $connect->();
            },
            on_error => sub {
                critf(shift);
                $connect->();
            },
		);
    };
    $connect = sub {
        $connector = AE::timer 0, 2, sub { $stream = $listener->() };
    };

    $connect->();
    $cv->recv;

}

sub delicious {
    my $self = shift;
    state $delicious = Net::Delicious->new( $self->{config}->{delicious} );
    return $delicious;
}

sub coro_head {
    my $self = shift;
    my $uri  = shift;
    http_head $uri, Coro::rouse_cb;
    my ( $data, $headers ) = Coro::rouse_wait;
    if ( $headers->{Status} ~~ [ 200, 301, 302, 304 ] ) {
        debugf( "expand: %s => %s", $uri, $headers->{URL} );
        return $headers->{URL};
    }
    else {
        debugf( "Status != 200. headers: %s", ddf($headers) );
        return $headers->{Redirect}->[0]->{URL}
            if exists $headers->{Redirect};
    }
}

sub _posts {
    my $self      = shift;
    my $delicious = $self->delicious;
    my @posts     = @_;
    debugf( "posts: %s", \@posts );
    if ( @posts > 0 ) {
        for my $post (@posts) {
            async {
                my $done = retry 3, 1, sub {
                    $post->{url} = $self->coro_head( $post->{url} );
                    $delicious->add_post($post);
                };
                infof( "Post %s done", $post->{url} )
                    if $done;
            };
        }
    }
}

1;
__END__

=head1 NAME

Tweet::ToDelicious - Links in your tweet to delicious.

=head1 SYNOPSIS

  use Tweet::ToDelicious;
  Tweet::ToDelicious->new($cfg)->run;

=head1 DESCRIPTION

use L<t2delicious.pl> instead of this module directly.

=head1 DEPENDENCIES

L<Config::Any>, L<YAML::XS>, L<Net::Delicious>, L<LWP::Protocol::https>, L<Coro>, L<AnyEvent::Twitter::Stream>, L<Net::OAuth>, L<Net::SSLeay>, L<List::MoreUtils>, L<Log::Minimal>, L<Sub::Retry>

=head1 SEE ALSO

L<AnyEvent::Twitter::Stream>, L<Net::Delicious>

=head1 AUTHOR

Yoshihiro Sasaki, E<lt>ysasaki at cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2011 by Yoshihiro Sasaki

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.14.2 or,
at your option, any later version of Perl 5 you may have available.

=cut