package OX::Meta::Role::Composite;
BEGIN {
  $OX::Meta::Role::Composite::AUTHORITY = 'cpan:STEVAN';
}
$OX::Meta::Role::Composite::VERSION = '0.14';
use Moose::Role;
use namespace::autoclean;

use Moose::Util 'does_role';

with 'OX::Meta::Role::Role';

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

    $self->$orig(@_);

    $self = Moose::Util::MetaRole::apply_metaroles(
        for => $self,
        role_metaroles => {
            application_to_class    => ['OX::Meta::Role::Application::ToClass'],
            application_to_role     => ['OX::Meta::Role::Application::ToRole'],
            application_to_instance => ['OX::Meta::Role::Application::ToInstance'],
        },
    );

    $self->_merge_routes;

    return $self;
};

sub _merge_routes {
    my $self = shift;

    my %routes;
    my %mounts;
    for my $role (@{ $self->get_roles }) {
        next unless does_role($role, 'OX::Meta::Role::Role');
        for my $route ($role->routes) {
            my $canonical = $route->canonical_path;
            if (exists $routes{$canonical}) {
                $routes{$canonical} = OX::Meta::Conflict->new(
                    path      => $canonical,
                    conflicts => [$routes{$canonical}, $route],
                );
            }
            else {
                $routes{$canonical} = $route;
            }
        }
        for my $mount ($role->mounts) {
            my $path = $mount->path;
            if (exists $mounts{$path}) {
                $mounts{$path} = OX::Meta::Conflict->new(
                    path      => $path,
                    conflicts => [$mounts{$path}, $mount],
                );
            }
            else {
                $mounts{$path} = $mount;
            }
        }
    }

    my %mixed;
    ROUTE: for my $route (values %routes) {
        for my $mount_path (keys %mounts) {
            my $mount = $mounts{$mount_path};
            (my $prefix = $mount_path) =~ s{/$}{};
            if ($route->path =~ m{^$mount_path\b}) {
                my @routes = $route->isa('OX::Meta::Conflict')
                    ? $route->conflicts
                    : $route;
                my @mounts = $mount->isa('OX::Meta::Conflict')
                    ? $mount->conflicts
                    : $mount;
                my $conflict = OX::Meta::Conflict->new(
                    path      => $route->canonical_path,
                    conflicts => [@routes, @mounts],
                );
                $self->_add_mixed_conflict($conflict);
                $mixed{$mount_path} = 1;
                next ROUTE;
            }
        }

        $self->_add_route($route);
    }

    delete $mounts{$_} for keys %mixed;

    for my $mount (values %mounts) {
        $self->_add_mount($mount);
    }
}

=for Pod::Coverage

=cut

1;
