package App::SCS;

use Module::Runtime qw(use_module);
use IO::All;
use Moo;

with 'App::SCS::Role::WithConfig';

has plugins => (is => 'ro', default => sub { [] });

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

sub _build_root_dir {
  my ($self) = @_;
  io->dir(io->dir($self->config->{root_dir})->absolute);
}

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

sub _build_share_dir {
  my ($self) = @_;
  io->dir($self->config->{share_dir}||$self->root_dir->catdir('share'));
}

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

sub _build_page_plugin_config {
  my ($self) = @_;
  return {
    plugin_map => {
      do {
        my %map = map $_->page_plugins, reverse @{$self->plugins};
        ref($_) or $_ = { class => $_, config => sub {} } for values %map;
        %map;
      }
    },
    defaults => [
      map $_->default_page_plugins, @{$self->plugins}
    ],
  };
}

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

sub _build_pages {
  my ($self) = @_;
  return use_module('App::SCS::PageSet')->new(
    base_dir => $self->share_dir->catdir('pages'),
    plugin_config => $self->page_plugin_config,
  );
}

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

sub _build_web {
  my ($self) = @_;
  return use_module('App::SCS::Web')->new(
    app => $self
  );
}

sub BUILD {
  my ($self) = @_;
  $self->load_plugin(Core => {});
  my @plist = @{$self->config->{plugins}||[]};
  while (my ($name, $conf) = splice @plist, 0, 2) {
    $self->load_plugin($name, $conf);
  }
}

sub load_plugin {
  my ($self, $name, $config) = @_;
  my $class = ($name =~ s/^\+// ? $name : "App::SCS::Plugin::${name}");
  push(
    @{$self->plugins},
    use_module($class)->new(
      app => $self,
      config => $config
    )
  );
  return;
}

sub run_if_script {
  my $self = shift;
  if (caller(1)) {
    return 1;
  } else {
    return $self->run;
  }
}

sub run {
  my $self = shift;
  my $env = {
    argv => \@ARGV,
    stdin => \*STDIN,
    stdout => \*STDOUT,
    stderr => \*STDERR,
  };
  foreach my $p (@{$self->plugins}) {
    return if $p->run_cli($env);
  }
  $self->web->run;
}

1;
