package SCSite;

use IO::All;
use SCSite::PageSet;
use Web::Simple;

{
  package SCSite::Link; use Moo; has $_ => (is => 'ro') for qw(title to);
}

has _topbar => (is => 'ro', default => sub { [
  map SCSite::Link->new(title => $_->[0], to => $_->[1] ),
    map [ /^(.*?)\s+(\S+)$/ ],
      split("\n", <<'ENDBAR')
Home /
About /about
News /news
Catalyst /catalyst
Servers /servers
Professional Services /services
Blogs /blog
ENDBAR
  ] }
);

has pages => (is => 'lazy');

has _layout_zoom => (is => 'lazy');

sub default_config {
  (
    pages_dir => 'share/content',
    template_dir => 'share/skin',
  )
}

sub _build_pages {
  my ($self) = @_;
  SCSite::PageSet->new(base_dir => $self->config->{pages_dir})
}

sub dispatch_request {
  my $self = shift;
  sub (/feed/**/) {
    $self->_http_response(500 => 'text/plain' => 'Not implemented');
  },
  sub (/) {
    $self->_page_http_response(200 => $self->_find_page('index'));
  },
  sub (/**) {
    [ 302, [ 'Location' => "/$_[1]/" ], [] ]
  },
  sub (/**/) {
    my ($code, $page) = map {
      $_ ? (200, $_) : (404, $self->_error_page(404))
    } $self->_find_page($_[1]);
    $self->_page_http_response($code => $page);
  }
}

sub _error_page {
  my ($self, $code) = @_;
  $self->_find_page("error_${code}");
}

sub _find_page {
  my ($self, $path) = @_;
  $self->pages->get({ path => $path });
}

sub _http_response {
  my ($self, $code, $type, $content) = @_;
  [ $code, [ 'Content-type' => $type ], [ $content ] ];
}

sub _page_http_response {
  my ($self, $code, $page) = @_;
  [ $code, [ 'Content-type' => 'text/html' ], $self->_render_page($page) ];
}

sub _render_page {
  my ($self, $page) = @_;
  my $zoom = $self->_layout_zoom;
  $zoom->select('.title')->replace_content($page->title)
       ->select('meta[name=description]')->replace_content($page->description)
       ->select('meta[name=keywords]')->replace_content($page->keywords)
       ->select('.topbar_entries')->repeat_content([
         map { my $e = $_; sub {
           $_->select('.entry')->replace_content($e->title)
             ->then->set_attribute(href => $e->to)
         } } @{$self->_topbar}
       ])
       ->select('.main')->replace_content(\$page->body)
       ->to_fh
}

sub _build__layout_zoom {
  my ($self) = @_;
  HTML::Zoom->from_file(
    io->dir($self->config->{template_dir})->catfile('layout.html')
  )->memoize;
}

sub run_if_script {
  return $_[0]->to_psgi_app if caller(1);
  my $class = shift;
  my @config_keys = keys %{{$class->default_config}};
  require Getopt::Long;
  my %config;
  Getopt::Long::GetOptions(
    map +("$_=s" => \$config{$_}), @config_keys
  );
  delete $config{$_} for grep !defined($config{$_}), keys %config;
  my $new = $class->new(config => \%config);
  $new->run(@_)
}

__PACKAGE__->run_if_script;
