package FixMyStreet::App::Controller::JSON;
use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller'; }

use JSON::MaybeXS;
use DateTime;
use DateTime::Format::ISO8601;
use FixMyStreet::DateRange;

=head1 NAME

FixMyStreet::App::Controller::JSON - Catalyst Controller

=head1 DESCRIPTION

Provide information as JSON

=head1 METHODS

=head2 problems

Provide JSON of new/fixed problems in a specified time range

=cut

sub problems : Local {
    my ( $self, $c, $path_type ) = @_;

    # get the type from the path - this is to deal with the historic url
    # structure. In futur
    $path_type ||= '';
    my $type =
        $path_type eq 'new'   ? 'new_problems'
      : $path_type eq 'fixed' ? 'fixed_problems'
      :                         '';

    # gather the parameters
    my $start_date = $c->get_param('start_date') || '';
    my $end_date = $c->get_param('end_date') || '';
    my $category = $c->get_param('category') || '';

    my $yyyy_mm_dd = qr{^\d{4}-\d\d-\d\d$};
    if (   $start_date !~ $yyyy_mm_dd
        || $end_date !~ $yyyy_mm_dd )
    {
        $c->stash->{error} = 'Invalid dates supplied';
        return;
    }

    # convert the dates to datetimes and trap errors
    my $range = FixMyStreet::DateRange->new(
        start_date => $start_date,
        end_date => $end_date,
        parser => DateTime::Format::ISO8601->new,
        formatter => $c->model('DB')->schema->storage->datetime_parser,
    );
    unless ($range->start && $range->end) {
        $c->stash->{error} = 'Invalid dates supplied';
        return;
    }

    # check that the dates are sane
    if ($range->start >= $range->end) {
        $c->stash->{error} = 'Start date after end date';
        return;
    }

    # check that the type is supported
    unless ( $type eq 'new_problems' || $type eq 'fixed_problems' ) {
        $c->stash->{error} = 'Invalid type supplied';
        return;
    }

    # query the database
    my ( @state, $date_col );
    if ( $type eq 'new_problems' ) {
        @state = FixMyStreet::DB::Result::Problem->open_states();
        $date_col = 'confirmed';
    } elsif ( $type eq 'fixed_problems' ) {
        @state = FixMyStreet::DB::Result::Problem->fixed_states();
        $date_col = 'lastupdate';
    }

    my $query = {
        $date_col => $range->sql,
        state => [ @state ],
        non_public => 0,
    };
    $query->{category} = $category if $category;
    my @problems = $c->cobrand->problems->search( $query, {
        order_by => { -asc => 'confirmed' },
        columns => [
            'id',       'title', 'bodies_str',   'category',
            'detail',   'name',  'anonymous', 'confirmed',
            'whensent', 'service',
            'latitude', 'longitude', 'used_map',
            'state', 'lastupdate',
        ]
    } );

    foreach my $problem (@problems) {
        $c->cobrand->call_hook(munge_problem_list => $problem);
        $problem->name( '' ) if $problem->anonymous == 1;
        $problem->service( 'Web interface' ) if $problem->service eq '';
        my $body_names = $problem->body_names;
        if (@$body_names) {
             $problem->bodies_str( join(' and ', @$body_names) );
        }
    }

    @problems = map { { $_->get_columns } } @problems;
    $c->stash->{response} = \@problems;
}

sub end : Private {
    my ( $self, $c ) = @_;

    my $response =
      $c->stash->{error}
      ? { error => $c->stash->{error} }
      : $c->stash->{response};

    $c->res->content_type('application/json; charset=utf-8');
    $c->res->body( encode_json( $response || {} ) );
}

__PACKAGE__->meta->make_immutable;

1;
