package CatalystX::Eta::Controller::Search;

use Moose::Role;
use Moose::Util::TypeConstraints;

requires 'list_GET';

around list_GET => \&Search_arround_list_GET;

sub Search_arround_list_GET{
    my $orig = shift;
    my $self = shift;

    my ($c) = @_;

    #print "      Search::around list_GET \n";

    my %may_search;

    if ( exists $self->config->{search_ok} ) {
        foreach my $key_ok ( keys %{ $self->config->{search_ok} } ) {
            if ( exists $c->req->params->{$key_ok} ) {
                $may_search{$key_ok} = $c->req->params->{$key_ok};

            }
            elsif ( exists $c->req->params->{"$key_ok:IN"} ) {

                push @{ $may_search{$key_ok}{'-or'} }, [ split /\n/, $c->req->params->{"$key_ok:IN"} ];

            }
            else {

                for my $exp (qw|< > >= <= +< +> +>= +<=|) {

                    if ( exists $c->req->params->{"$key_ok:$exp"} ) {
                        my $tmp = "$exp";    # not more read only
                        $tmp =~ s/^(\+)?//;
                        my $gp = $1 && $1 eq '+' ? '-and' : '-or';
                        push @{ $may_search{$key_ok}{$gp} }, { $tmp => $c->req->params->{"$key_ok:$exp"} };
                    }
                }
            }
        }
    }

    foreach my $key ( keys %may_search ) {

        my $type = $self->config->{search_ok}{$key};
        my $val  = $may_search{$key};

        $may_search{$key} = undef, next
          if ( ( $type eq 'Bool' || $type eq 'Int' || $type eq 'Num' || ref $type eq 'MooseX::Types::TypeDecorator' )
            && $val eq '' );

        my $cons = Moose::Util::TypeConstraints::find_or_parse_type_constraint($type);

        $self->status_bad_request( $c, message => "Unknown type constraint '$type'" ), $c->detach
          unless defined($cons);

        if ( ref $val eq 'HASH' ) {

            # much groups
            foreach my $gp ( keys %$val ) {

                foreach my $a_val ( @{ $val->{$gp} } ) {
                    my $checkval = ref $a_val eq 'HASH' ? $a_val->{ ( keys %$a_val )[0] } : $a_val;

                    if ( !$cons->check($checkval) ) {
                        $self->status_bad_request( $c, message => "invalid param $key for $checkval" );
                        $c->detach;
                    }
                }
            }

            # such valided

        }
        else {
            my $checkval = $val;
            if ( !$cons->check($checkval) ) {

                $self->status_bad_request( $c, message => "invalid param $key" ), $c->detach;
            }
        }
    }

    my $base = $self->config->{search_base} || 'me';
    foreach my $k ( keys %may_search ) {
        if ( $k !~ /\./ ) {
            my $such_val = delete $may_search{$k};

            if ( ref $such_val eq 'HASH' ) {

                for my $op ( keys %$such_val ) {

                    push @{ $may_search{$op} }, map { +{ "$base.$k" => $_ } } @{ $such_val->{$op} };
                }

            }
            else {
                $may_search{"$base.$k"} = $such_val;
            }
        }else{
            die 'TODO...';
        }
    }

    $c->stash->{collection} = $c->stash->{collection}->search( {%may_search} )
      if %may_search;

    if ( $c->req->params->{limit_rows} && $c->req->params->{limit_rows} =~ /^[0-9]+$/ ) {
        $c->stash->{collection} = $c->stash->{collection}->search(
            undef,
            {
                rows => $c->req->params->{limit_rows}
            }
        );
    }

    $self->$orig(@_);
};

1;

