package HTTP::Router::Mapper;

use Moose;
use Hash::Merge qw(merge);
use HTTP::Router::Route;
use HTTP::Router::Routes;
use namespace::clean -except => ['meta'];

has 'routeset' => (
    is       => 'rw',
    isa      => 'HTTP::Router::Routes',
    required => 1,
);

has 'route' => (
    is        => 'rw',
    isa       => 'HTTP::Router::Route',
    predicate => 'has_route',
);

has 'path' => (
    is      => 'rw',
    isa     => 'Str',
    default => '',
    lazy    => 1,
);

has 'conditions' => (
    is      => 'rw',
    isa     => 'HashRef',
    default => sub { +{} },
    lazy    => 1,
);

has 'params' => (
    is      => 'rw',
    isa     => 'HashRef',
    default => sub { +{} },
    lazy    => 1,
);

sub freeze {
    my $self = shift;

    my $route = HTTP::Router::Route->new(
        path       => $self->path,
        params     => $self->params,
        conditions => $self->conditions,
    );

    $self->routeset->push($route);
    $self->route($route);

    return $self;
}

sub clone {
    my ($self, %params) = @_;
    return $self->meta->clone_instance($self, %params, routeset => $self->routeset);
}

sub match {
    my $self = shift;
    return $self if $self->has_route;

    my $block = ref $_[-1] eq 'CODE' ? pop : undef;
    my ($path, $conditions) = @_;

    my $mapper = $self->clone(
        path       => $self->path . $path,
        conditions => merge($conditions || {}, $self->conditions),
        params     => $self->params,
    );
    if ($block) {
        local $_ = $mapper;
        $block->($_);
    }

    return $mapper;
}


sub to {
    my $self = shift;
    return $self if $self->has_route;

    my $block = ref $_[-1] eq 'CODE' ? pop : undef;
    my $params = shift || {};

    my $mapper = $self->clone(
        path       => $self->path,
        conditions => $self->conditions,
        params     => merge($params, $self->params),
    );
    if ($block) {
        local $_ = $mapper;
        $block->($_);
    }
    else {
        $mapper->freeze;
    }

    return $mapper;
}

{
    my $meta = __PACKAGE__->meta;
    my $method = $meta->get_method('to');
    $meta->add_method($_ => $method) for qw(with register);
}

no Moose; __PACKAGE__->meta->make_immutable;

=head1 NAME

HTTP::Router::Mapper

=head1 METHODS

=head2 match($path, $conditions?)

=head2 to($params?)

=head1 PROPERTIES

=head2 routeset

=head2 route

=head2 path

=head2 conditions

=head1 INTERNALS

=head2 register

=head1 AUTHOR

NAKAGAWA Masaki E<lt>masaki@cpan.orgE<gt>

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 SEE ALSO

L<HTTP::Router>, L<HTTP::Router::Route>

=cut
