package App::EzPz::Web;

use Module::Runtime qw(use_module);
use App::EzPz::UserStore;
use HTML::Zoom;
use Web::Simple;

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

sub _build_users {
  my ($self) = @_;
  my $config = $self->config;
  return App::EzPz::UserStore->new(
    htpasswd_file => $config->{htpasswd_file},
    ($config->{ezmlm_bindir}
      ? (ezmlm_config => {
           bindir => $config->{ezmlm_bindir},
           list_base_dir => $config->{list_base_dir},
        })
      : ())
  );
}

sub default_config {
  (
    htpasswd_file => 'test-config/htpasswd',
    ezmlm_bindir => 'test-ezmlm/bin',
    list_base_dir => 'test-lists',
  )
}

sub dispatch_request {
  my ($self) = @_;
  my $users = $self->users;
  my $current_user;
  sub () {
    return if $_[PSGI_ENV]->{REMOTE_USER};
    return use_module('Plack::Middleware::Auth::Basic')->new(
      authenticator => sub { $users->check_password(@_) }
    )
  },
  sub () {
    $current_user = $users->get(my $name = $_[PSGI_ENV]->{REMOTE_USER});
    return [
      401, [ 'Content-type' => 'text/plain' ], [ "No such user $name" ]
    ] unless $current_user;
    return;
  },
  sub (/) {
    $self->_render_front_page($current_user);
  },
  sub (/list/*/...) {
    my $list = $current_user->get_list($_[1]);
    return unless $list;
    sub (/) {
      $self->_list_dispatchers($list),
      sub () { $self->_render_list_page($list) };
    },
    sub (/deny/|/allow/|/mod/|/digest/) {
      sub (/*/) {
        my $sublist = $list->${\$_[1]};
        $self->_list_dispatchers($sublist),
        sub () { $self->_render_sublist_page($sublist) };
      },
    },
  }
}

sub _list_dispatchers {
  my ($self, $list) = @_;
  sub (POST) {
    sub (%add=) {
      $list->add_member($_[1]);
      return;
    },
    sub (%remove=) {
      $list->remove_member($_[1]);
      return;
    },
  }
}

sub _zoom_for {
  my ($self, $name) = @_;
  my $my_file = __FILE__;
  $my_file =~ s/\.pm//;
  return HTML::Zoom->from_file("${my_file}/_templates/${name}.html");
}

sub _render_page {
  my ($self, $name, $code) = @_;
  return [
    200, [ 'Content-type' => 'text/html' ],
    [ $self->_zoom_for($name)->${\sub { local $_ = $_[0]; &$code }}->to_html ]
  ];
}

sub _render_front_page {
  my ($self, $user) = @_;
  return $self->_render_page(index => sub {
    $_->replace_content('.user-name',$user->username)
      ->repeat('.list', [
          map {
            my $name = $_;
            sub {
              $_->select('.list-link')
                ->replace_content($name)
                ->then
                ->set_attribute(href => "/list/${name}/");
            }
          } $user->list_names
        ]);
  });
}

sub _render_list_page {
  my ($self, $list) = @_;
  $self->_render_listcore_page(
    $list, [
      map [ ucfirst($_)." list", "${_}/" ], qw(allow deny mod digest)
    ]
  );
}

sub _render_sublist_page {
  my ($self, $list) = @_;
  $self->_render_listcore_page(
    $list, [ [ "Back to list", "../" ] ],
  );
}

sub _render_listcore_page {
  my ($self, $list, $links) = @_;
  $self->_render_page(list => sub {
    $_->replace_content('.list-name', $list->name)
      ->repeat('.list-link', [
          map {
            my ($name, $href) = @$_;
            sub {
              $_->select('.list-link-anchor')
                ->replace_content($name)
                ->then
                ->set_attribute(href => $href);
            }
          } @$links
        ])
      ->repeat('.list-member', [
          map {
            my $email = $_;
            sub {
              $_->replace_content('.list-member-name', $email)
                ->set_attribute('.list-member-remove', value => $email);
            }
          } $list->members
        ]);
  });
}

__PACKAGE__->run_if_script;
