package WebService::Strava::Athlete;

use v5.010;
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
use Scalar::Util::Reftype;
use Carp qw(croak);
use Data::Dumper;
use Method::Signatures 20140224;
use Moo;
use experimental 'switch';
use namespace::clean;

# ABSTRACT: A Strava Athlete Object

our $VERSION = '0.06'; # VERSION: Generated by DZP::OurPkg:Version


# Validation functions

my $Id = sub {
  if ($_[0]) {
    croak "$_[0] isn't a valid id" unless looks_like_number $_[0];
  }
};

my $Ref = sub {
  croak "auth isn't a 'WebService::Strava::Auth' object!" unless reftype( $_[0] )->class eq "WebService::Strava::Auth";
};

my $Bool = sub {
  croak "$_[0] must be 0|1" unless $_[0] =~ /^[01]$/;
};

# Debugging hooks in case things go weird. (Thanks @pjf)

around BUILDARGS => sub {
  my $orig  = shift;
  my $class = shift;
  
  if ($WebService::Strava::DEBUG) {
    warn "Building task with:\n";
    warn Dumper(\@_), "\n";
  }
  
  return $class->$orig(@_);
};

# Authentication Object
has 'auth'            => ( is => 'ro', required => 1, isa => $Ref );

# Defaults + Required
has 'id'                      => ( is => 'ro', isa => $Id );
has '_build'                  => ( is => 'ro', default => sub { 1 }, isa => $Bool );

# Athlete API
has 'name'                    => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'resource_state'          => ( is => 'ro', lazy => 1, builder => '_build_athlete' ); 
has 'firstname'               => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'lastname'                => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'profile_medium'          => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'profile'                 => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'city'                    => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'state'                   => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'country'                 => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'sex'                     => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'friend'                  => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'follower'                => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'premium'                 => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'created_at'              => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'updated_at'              => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'approve_followers'       => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'friend_count'            => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'mutual_friend_count'     => ( is => 'ro', lazy => 1, builder => '_build_athlete' ); 
has 'date_preference'         => ( is => 'ro', lazy => 1, builder => '_build_athlete' ); 
has 'measurement_preference'  => ( is => 'ro', lazy => 1, builder => '_build_athlete' ); 
has 'email'                   => ( is => 'ro', lazy => 1, builder => '_build_athlete' ); 
has 'ftp'                     => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'clubs'                   => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'bikes'                   => ( is => 'ro', lazy => 1, builder => '_build_athlete' );
has 'shoes'                   => ( is => 'ro', lazy => 1, builder => '_build_athlete' );

sub BUILD {
  my $self = shift;

  if ($self->{_build}) {
    $self->_build_athlete();
  }
  return;
}

method _build_athlete() {
  my $athlete;
  if ($self->id) {
    $athlete = $self->auth->get_api("/athletes/$self->{id}");
  } else {
    $athlete = $self->auth->get_api("/athlete");
  }
 
  foreach my $key (keys %{ $athlete }) {
    given ( $key ) {
      when      (/bikes/)   { $self->_instantiate("Athlete::Gear::Bike", $key, $athlete->{$key}); }
      when      (/shoes/)   { $self->_instantiate("Athlete::Gear::Shoe", $key, $athlete->{$key}); }
      when      (/clubs/)   { $self->_instantiate("Club", $key, $athlete->{$key}); }
      default               { $self->{$key} = $athlete->{$key}; }
    }
  }
  
  return;
}

use WebService::Strava::Athlete::Gear::Bike;
use WebService::Strava::Athlete::Gear::Shoe;
use WebService::Strava::Club;

method _instantiate($type, $key, $data) {
  my $index = 0;
  foreach my $item (@{$data}) {
    @{$data}[$index] = "WebService::Strava::$type"->new(auth => $self->auth, id => $item->{id}, _build => 0);
    $index++;
  }
  $self->{$key} = $data;
  return;
}


use WebService::Strava::Athlete::Segment_Effort;

method list_records(:$efforts = 25,:$page = 1) {
  # TODO: Handle pagination better use #4's solution when found.
  my $records = $self->auth->get_api("/athletes/$self->{id}/koms?per_page=$efforts&page=$page");
  my $index = 0;
  foreach my $record (@{$records}) {
    @{$records}[$index] = WebService::Strava::Athlete::Segment_Effort->new(id => $record->{id}, auth => $self->auth, _build => 0);
    $index++;
  }
  return $records;
};

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

WebService::Strava::Athlete - A Strava Athlete Object

=head1 VERSION

version 0.06

=head1 SYNOPSIS

  my $athlete = WebService::Strava::Athelete->new( auth => $auth, [id => '229781'] );

=head1 DESCRIPTION

  Upon instantiation will retrieve the athlete matching the id.
  Requires a pre-authenticated WebService::Strava::Auth object.

=head1 METHODS

=head2 list_records()

  $athlete->list_records([page => 2], [efforts => 100])'

Returns an arrayRef K|Q of Mountain + Course record Segment effort objects for the instantiated athlete. Takes 2 optional
parameters of 'page' and 'efforts'.

The results are paginated and a maximum of 200 results can be returned
per page.

=head1 AUTHOR

Leon Wright < techman@cpan.org >

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Leon Wright.

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

=cut