package App::SCS::Plugin::Feeds::Generator;

use URI;
use Moo;
no warnings 'once';

has pages => (is => 'ro', required => 1);

has mounted_at => (is => 'ro', required => 1);

sub feed_http_response {
  my ($self, $code, $feed_config, $env) = @_;
  $self->_feed_response(
    $code, $self->_config_to_data($feed_config, $env)
  );
}

sub _config_to_data {
  my ($self, $config, $env) = @_;
  my $url_scheme = $env->{'psgi.url_scheme'} || "http";
  my $url_port = $env->{SERVER_PORT}||80;
  my $base_url = URI->new(
    $url_scheme
    .'://'
    .($env->{HTTP_HOST}
      or (
        ($env->{SERVER_NAME} || "")
        .($url_scheme eq 'http' && $url_port == 80
           ? ''
           : ":${url_port}"
         )
      ))
    .($env->{SCRIPT_NAME} || '/')
  );
  my $abs = sub { URI->new_abs($_[0], $base_url)->as_string };
  my $base_page = $self->pages->get({ path => $config->{base} });
  my @entry_pages = $base_page->children(%{$config->{entries}})
                              ->latest(10)->flatten;
  my $updated = (sort map $_->created, @entry_pages)[-1];
  my $base = $self->mounted_at;
  +{
     %$config,
     id => $abs->("${base}/${\$config->{base}}/"),
     web_url => $abs->($config->{base}.'/'),
     feed_url => $abs->("${base}/${\$config->{base}}/"),
     updated => join('T', split(' ',$updated)).'Z',
     entries => [ map {
      my $page_url = $abs->(do { (my $p = $_->path) =~ s/^\///; "$p/" });
      +{
         title => $_->title,
         summary_html => do {
           use HTML::Tags;
           join '', HTML::Tags::to_html_string(<p>, $_->description, </p>)
         },
         content_html => $self->_content_html($_, $base_url, $page_url),
         created => join('T', split(' ',$_->created)).'Z',
         web_url => $page_url,
       }
    } @entry_pages ],
  }
}

sub _feed_response {
  my ($self, $code, $data) = @_;
  [ $code,
    [ 'Content-type' => 'application/atom+xml' ],
    [ $self->_feed_string($data) ]
  ]
}

sub _feed_string {
  my ($self, $data) = @_;
  XML::Tags::to_xml_string(
    $self->_feed_data_to_tags($data)
  );
}

sub _feed_data_to_tags {
  my ($self, $data) = @_;
  use XML::Tags qw(
    feed title subtitle link id
  );
  my ($web_url, $feed_url) = @{$data}{qw(web_url feed_url)};
  (\'<?xml version="1.0" encoding="UTF-8"?>', "\n",
  <feed xmlns="http://www.w3.org/2005/Atom">, "\n",
    '  ', <title type="text">, $data->{title}, </title>, "\n",
    ($data->{subtitle}
      ? ('  ', <subtitle type="text">, $data->{subtitle}, </subtitle>, "\n",)
      : ()),
    '  ', <link rel="alternate" type="text/html" href="${web_url}" />, "\n",
    '  ', <link rel="self" type="application/atom+xml" href="${feed_url}" />, "\n",
    '  ', <updated>, $data->{updated}, </updated>, "\n",
    '  ', <id>, $data->{id}, </id>, "\n",
    (map $self->_entry_data_to_tags($_), @{$data->{entries}}),
  </feed>);
}

sub _entry_data_to_tags {
  my ($self, $data) = @_;
  use XML::Tags qw(
    entry title author name link id published updated summary content
  );
  my $web_url = $data->{web_url};
  '  ', <entry>, "\n",
    '    ', <title>, $data->{title}, </title>, "\n",
    '    ', <author>, <name>, "Shadowcat Staff", </name>, </author>, "\n",
    '    ', <link href="${web_url}" />, "\n",
    '    ', <id>, $web_url, </id>, "\n",
    '    ', <published>, $data->{created}, </published>, "\n",
    '    ', <updated>, ($data->{created}||$data->{updated}), </updated>, "\n",
    ($data->{summary_html}
      ? ('    ', <summary type="html">, \('<![CDATA['.$data->{summary_html}.']]>'), </summary>, "\n")
      : ()
    ),
    '    ', <content type="html">, \('<![CDATA['.$data->{content_html}.']]>'), </content>, "\n",
  '  ', </entry>, "\n";
}

sub _content_html {
  my ($self, $page, $base_url, $page_url) = @_;
  my @ev;
  HTML::Zoom->from_html($page->html)
            ->collect(body => { into => \@ev })
            ->run;
  HTML::Zoom->from_events(\@ev)->to_html;
}

1;
