The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package OX::Application::Role::Sugar;
BEGIN {
  $OX::Application::Role::Sugar::AUTHORITY = 'cpan:STEVAN';
}
{
  $OX::Application::Role::Sugar::VERSION = '0.13';
}
use Moose::Role;
use namespace::autoclean;

use Bread::Board;
use Plack::App::URLMap;

use OX::Util;

has _manual_router_config => (
    is  => 'rw',
    isa => 'HashRef',
);

sub BUILD { }
after BUILD => sub {
    my $self = shift;

    my $manual_router_config = $self->has_service('RouterConfig')
        ? $self->resolve(service => 'RouterConfig')
        : {};
    $self->_manual_router_config($manual_router_config);

    $self->regenerate_router_config;
};

sub regenerate_router_config {
    my $self = shift;

    my $manual_router_config = $self->_manual_router_config;
    my $sugar_router_config = $self->meta->router_config;

    container $self => as {
        service RouterConfig => {
            %$manual_router_config,
            %$sugar_router_config,
        };
    };
}

around build_middleware => sub {
    my $orig = shift;
    my $self = shift;

    my @middleware = map { $_->resolve($self) } $self->meta->all_middleware;

    return [
        @{ $self->$orig(@_) },
        @middleware,
    ];
};

around build_app => sub {
    my $orig = shift;
    my $self = shift;

    my $app = $self->$orig(@_);
    return $app unless $self->meta->has_mounts;

    my $urlmap = Plack::App::URLMap->new;

    for my $mount ($self->meta->mounts) {
        if ($mount->isa('OX::Meta::Mount::App')) {
            $urlmap->map($mount->path => $mount->app);
        }
        elsif ($mount->isa('OX::Meta::Mount::Class')) {
            my $service = Bread::Board::ConstructorInjection->new(
                name         => '__ANON__',
                class        => $mount->class,
                dependencies => $mount->dependencies,
                parent       => $self,
            );
            my $app = $service->get;
            $urlmap->map($mount->path => $app->to_app);
        }
        else {
            die "Unknown mount type for path " . $mount->path . ": "
              . blessed($mount);
        }
    }

    $urlmap->map('/' => $app)
        unless $self->meta->has_mount_for('/');

    return $urlmap->to_app;
};

around to_app => sub {
    my $orig = shift;
    my $self = shift;

    return $self->$orig(@_)
        unless $self->meta->has_middleware_dependencies;

    # need to re-resolve for every request, to ensure that middleware
    # dependencies are correct - otherwise, a middleware that depends on a
    # service in an app will only resolve it once, at to_app time
    return sub {
        my ($env) = @_;
        $self->$orig(@_)->($env);
    };
};

=pod

=for Pod::Coverage
  BUILD
  regenerate_router_config

=cut

1;