package A;
sub b { }
1;

package Bar;
sub foo { }
1;

package Bar::Foo;
sub baz { }
1;

use strict;
use warnings;

BEGIN {
    my $DOWARN = 0;
    $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN }
}

use Test::More;
use Kelp::Routes;

my $r = Kelp::Routes->new;

# Basic
#
{
    $r->add( '/a' => 'a#b' );
    is_deeply _d( $r, qw/pattern to/ ), [
        {
            pattern => '/a',
            to      => 'A::b'
        }
      ];
}

# Via method
#
{
    $r->clear;
    $r->add( [ POST => '/a' ] => 'a#b' );
    is_deeply _d( $r, qw/method pattern to/ ), [
        {
            method  => 'POST',
            pattern => '/a',
            to      => 'A::b'
        }
      ];
}

# Odd method
#
{
    $r->clear;
    $r->add( [ MOST => '/a' ] => 'a#b' );
    is_deeply _d( $r, qw/method pattern to/ ), [
        {
            method  => 'MOST',
            pattern => '/a',
            to      => 'A::b'
        }
      ];
}

# Sub
#
{
    $r->clear;
    $r->add( '/a' => sub { } );
    is ref( $r->routes->[0]->to ), 'CODE';
}

# Not hash
#
{
    $r->clear;
    $r->add( '/a' => [] );
    is_deeply $r->routes, [];
}

# Weird key
#
{
    $r->clear;
    $r->add( { a => 1 }, 'a#b' );
    is_deeply $r->routes, [];

    $r->add( [ POST => { a => 1 } ], 'a#b' );
    is_deeply $r->routes, [];
}

# Missing destination
#
{
    $r->clear;
    $r->add( '/a' => { name => 'a' } );
    is_deeply $r->routes, [];
}

# Key trumps method in the value
{
    $r->clear;
    $r->add( [ POST => '/a' ] => { to => 'a', method => 'PUT' } );
    is_deeply _d( $r, qw/method/ ), [ { method => 'POST' } ];
}

# Regex
#
{
    $r->clear;
    my $re = qr{^/a/(\w+)$};
    $r->add( $re, 'bar#foo' );
    is_deeply _d( $r, qw/pattern/ ), [
        {
            pattern => $re
        }
      ];
}

# Hash
#
{
    $r->clear;
    my $hash = {
        name  => 'james',
        check => { a => '\d' },
        to    => 'bar#foo'
    };
    $r->add( '/:a' => $hash );
    is_deeply _d( $r, qw/name check to/ ), [
        {
            name  => 'james',
            check => { a => '\d' },
            to    => 'Bar::foo'
        }
      ];
}

# Base
#
{
    $r->clear;
    $r->base('Bar');
    $r->add( '/a' => 'foo#baz' );
    is_deeply _d( $r, qw/to/ ), [
        {
            to => 'Bar::Foo::baz'
        }
      ];
    $r->base('');
}

# Base + fully qualified name
{
    $r->clear;
    $r->base('Bar');
    $r->add( '/a' => '+Plack::Util::load_class' );
    is_deeply _d( $r, qw/to/ ), [
        {
            to => 'Plack::Util::load_class'
        }
      ];

    $r->clear;
    $r->add( '/a' => '+plack#util#load_class');
    is_deeply _d( $r, qw/to/ ), [
        {
            to => 'Plack::Util::load_class'
        }
      ];

    $r->base('');
}

# Tree
#
{

    # Tree not ARRAY
    $r->clear;
    $r->add(
        '/user' => {
            tree => { a => 1, b => 2 }
        }
    );
    is_deeply $r->routes, [];

    # Tree no name
    $r->clear;
    $r->add(
        '/a' => {
            to   => 'a',
            tree => [
                '/b' => { name => 'b', to => 'a#b' },
                '/c' => 'a#c'
            ]
        }
    );
    is_deeply _d( $r, 'name' ), [ {}, { name => 'b' }, {} ];

    # Good tree
    $r->clear;
    $r->add(
        '/user' => {
            name => 'user',
            to   => 'bar#user',
            tree => [
                '/id'   => { to => 'bar#id',   name => 'id' },
                '/edit' => { to => 'bar#edit', name => 'edit' },
                [ DELETE => '/id' ] => { to => 'bar#del' => name => 'delete' },
                '/change' => {
                    to   => 'bar#change',
                    name => 'change',
                    tree => [
                        '/name' => { to => 'bar#change_name', name => 'name' },
                        [ PUT  => '/email' ] =>
                          { to => 'bar#change_email', name => 'email' }
                    ]
                }
            ]
        }
    );

    is_deeply _d( $r, qw/pattern name to method/ ), [
        {
            pattern => '/user',
            name    => 'user',
            to      => 'Bar::user',
        }, {
            pattern => '/user/id',
            name    => 'user_id',
            to      => 'Bar::id',
        }, {
            pattern => '/user/edit',
            name    => 'user_edit',
            to      => 'Bar::edit',
        }, {
            pattern => '/user/id',
            name    => 'user_delete',
            to      => 'Bar::del',
            method  => 'DELETE'
        }, {
            pattern => '/user/change',
            name    => 'user_change',
            to      => 'Bar::change'
        }, {
            pattern => '/user/change/name',
            name    => 'user_change_name',
            to      => 'Bar::change_name'
        }, {
            pattern => '/user/change/email',
            name    => 'user_change_email',
            to      => 'Bar::change_email',
            method  => 'PUT'
        }
      ];
}

sub _d {
    my ( $r, @fields ) = @_;
    my @o = ();
    for my $route ( @{ $r->routes } ) {
        my @a = scalar(@fields) ? @fields : keys %{$route};
        my %h = ();
        for my $k (@a) {
            $h{$k} = $route->{$k} if ( defined $route->{$k} );
        }
        push @o, \%h;
    }
    return \@o;
}

done_testing;