package Newslash::FeedFetcher;

use strict;
use warnings;
use utf8;
use feature ':5.10';

use YAML qw(LoadFile);
use constant CONF_PATH => "/etc/newslash/newslash.conf";

use Newslash::Model::Feeds;
use Data::Dumper;
use DateTime::Format::MySQL;
use Newslash::Util;
use File::Spec;
use Mojo::Log;


sub new {
    my $class = shift;
    bless {_config => {} }, $class;
}

sub config {
    my ($self, $new_val) = @_;
    $self->{_config} = $new_val if defined $new_val;
    return $self->{_config};
}

sub feeds {
    my ($self, $new_val) = @_;
    $self->{_feeds} = $new_val if defined $new_val;
    return $self->{_feeds};
}

sub _detect_home {
    my ($self,) = @_;

    # Environment variable
    my $home;
    if ($ENV{MOJO_HOME}) {
	$home = $ENV{MOJO_HOME};
    }
    else {
	my $path = $INC{"Newslash/FeedFetcher.pm"};
	my @terms = split(/[\/\\]/, $path);
	while (@terms) {
	    my $last = pop(@terms);
	    if ($last =~ m/^(lib|blib)$/) {
		$home = File::Spec->catdir(@terms);
		last;
	    }
	}
    }
    return $home;
}

sub _load_config {
    my $self = shift;
    my $config_file;

    if (-e CONF_PATH) {
	$config_file = CONF_PATH;
    }
    else {
	my $home = $self->_detect_home;
	if ($home) {
	    $config_file = File::Spec->catdir($home, "newslash-feedfetcher.yaml");
	    if (! -e $config_file) {
		$config_file = File::Spec->catdir($home, "newslash-web.yaml");
	    }
	}
   }

    my $config = eval { LoadFile($config_file) };
    die qq{Can't parse config "$config_file": $@} if $@;
    die qq{Invalid config "$config_file"} unless ref $config eq 'HASH';

    return $config;
}

sub run {
    my $self = shift;
    my $log = Mojo::Log->new;

    if ($ENV{MOJO_LOG_LEVEL}) {
	$log->level($ENV{MOJO_LOG_LEVEL});
    }
    else {
	$log->level("warn");
    }

    my $config = $self->_load_config;
    $self->config($config);

    my $feeds = new Newslash::Model::Feeds($self->config);
    $self->feeds($feeds);

    my $rs = $feeds->select;
    if (!$rs) {
        die "cannot retrieve feed infomations from database.";
    }
    for my $feed (@$rs) {
        if ($feed->{status} ne "active") {
	    $log->info("$feed->{title} is not active. skip ...");
            next;
        }
	$log->info("fetch $feed->{url} ...");

        my $f = $feeds->fetch_url(\$feed->{url}, $config->{FeedFetcher} || {});
        my $now = DateTime::Format::MySQL->format_datetime(DateTime->now);
        if (!$f) {
            my $error = $feeds->last_error;
            $log->error("fetch $feed->{url} failed - $error.");
            $feeds->update(feed_id => $feed->{feed_id},
                           latest_fetch_time => $now,
                           latest_fetch_result => $feeds->last_errorno);
            next;
        }
        $feeds->update(feed_id => $feed->{feed_id},
                       latest_fetch_time => $now,
                       latest_fetch_result => 200);

        for my $item ($f->entries) {
            my $content = $item->content->body;
            my $type = $item->content->type;
            my $modified = $item->modified || $item->issued;
            #warn $content;
            #warn $type;
            #warn $modified;

            my $id = $feeds->items->create(feed_id => $feed->{feed_id},
                                           url => $item->link || "",
                                           title => $item->title || "",
                                           content => $content,
                                           content_type => $type,
                                           modified => $modified,
                                          );
            if (!defined $id) {
                my $error = $feeds->last_error;
                $log->error("cannot create feed item: $error");
            }
            else {
                if ($id == 0) {
                    $log->debug("update item " . $item->link . " (feed_id: $feed->{feed_id})");
                }
                else {
                    $log->debug("create item " . $item->link . " (feed_id: $feed->{feed_id}, item_id: $id)");
                }
            }
        }
    }

    return 0;
}

1;
