package WebService::Shutterstock::Customer;
BEGIN {
  $WebService::Shutterstock::Customer::AUTHORITY = 'cpan:BPHILLIPS';
}
{
  $WebService::Shutterstock::Customer::VERSION = '0.002';
}

# ABSTRACT: Class allowing API operations in the context of a specific customer

use strict;
use warnings;
use Moo;
use WebService::Shutterstock::Subscription;
use Carp qw(croak);
use JSON qw(encode_json);

with 'WebService::Shutterstock::AuthedClient';


has account_id => ( is => 'lazy' );
sub _build_account_id {
	my $self = shift;
	my $client = $self->client;
	$client->GET( sprintf( '/customers/%s.json', $self->username ), $self->with_auth_params );
	my $data = $client->process_response;
	return $data->{account_id};
}


has subscriptions => ( is => 'lazy' );
sub _build_subscriptions {
	my $self = shift;
	$self->client->GET( sprintf( '/customers/%s/subscriptions.json', $self->username ), $self->with_auth_params );
	my $subscriptions = $self->client->process_response;
	return [ map { $self->new_with_auth( 'WebService::Shutterstock::Subscription', %$_ ) } @$subscriptions ]
}


sub subscription {
	my $self = shift;
	my ( $subscription, @extra ) = $self->find_subscriptions(@_);
	return $subscription;
}


sub find_subscriptions {
	my $self = shift;
	my %criteria = @_;
	my $filter = sub {
		my $s = shift;
		foreach my $m(keys %criteria){
			croak "Invalid subscription filter key '$m': no such attribute on WebService::Shutterstock::Subscription" if !$s->can($m);
			my $value = $s->$m;
			my $matcher = $criteria{$m};
			if(ref $matcher eq 'CODE'){
				local $_ = $value;
				return unless $matcher->($value);
			} elsif(ref $matcher eq 'Regexp'){
				return unless $value =~ $matcher;
			} else {
				return unless $value eq $matcher;
			}
		}
		return 1;
	};
	return grep { $filter->($_) } @{ $self->subscriptions };
}


sub lightboxes {
	my $self = shift;
	my $extended = shift || 0;
	$self->client->GET(
		sprintf(
			'/customers/%s/lightboxes%s.json',
			$self->username, $extended ? '/extended' : ''
		),
		$self->with_auth_params
	);
	my $lightboxes = $self->client->process_response;
	return [ map {$self->new_with_auth('WebService::Shutterstock::Lightbox', %$_) } @$lightboxes ];
}


sub lightbox {
	my $self = shift;
	my $id = shift;
	my $lightbox = $self->new_with_auth('WebService::Shutterstock::Lightbox', lightbox_id => $id);
	eval { $lightbox->load; 1 } or do {
		my $e = $@;
		if(eval { $e->isa('WebService::Shutterstock::Exception') } && ($e->code eq 404 || $e->code eq 500)){
			$lightbox = undef;
		} else {
			die $e;
		}
	};
	return $lightbox;
}


sub downloads {
	my $self = shift;
	my %args = @_;
	$self->client->GET(
		sprintf( '/customers/%s/images/downloads.json', $self->username ),
		$self->with_auth_params(%args) );
	return $self->client->process_response;
}


sub license_image {
	my $self     = shift;
	my %args     = @_;

	my $image_id = $args{image_id} or croak "Must specify image_id to license";
	my $metadata = $args{metadata} || {purchase_order => '', job => '', client => '', other => ''};
	my $size     = $args{size};

	my $single_finder = sub {
		my %criteria = @_;
		my @matching = $self->find_subscriptions( %criteria, is_active => 1 );
		if ( @matching == 0 ) {
			croak "Unable to find a subscription to license images";
		} elsif ( @matching > 1 ) {
			croak "You have more than one active subscription.  Please provide a WebService::Shutterstock::Subscription object or specify unique critiria to identify which subscription you would like to use (i.e. { license => 'standard' } or { id => 26374582 } )";
		}
		return $matching[0];
	};


	my $subscription;
	if(my $sub_arg = $args{subscription}){
		if(!ref($sub_arg)){
			$subscription = $self->subscription( id => $sub_arg );
		} elsif(ref($sub_arg) eq 'HASH'){
			$subscription = $single_finder->( %$sub_arg );
		} elsif(eval { $sub_arg->isa('WebService::Shutterstock::Subscription') }){
			$subscription = $sub_arg;
		}
	} else {
		$subscription = $single_finder->();
	}

	if(!$subscription){
		croak "Must specify a subscription to license images under";
	}

	my @valid_sizes = $subscription->sizes_for_licensing;
	if(!$size && @valid_sizes == 1){
		$size = $valid_sizes[0];
	}
	croak "Must specify size of image to license" if !$size;

	if ( !grep { $_ eq $size } @valid_sizes ) {
		croak "Invalid size '$size', please specify a valid size: " . join(", ", @valid_sizes);
	}

	my $format = $size eq 'vector' ? 'eps' : 'jpg';
	my $client = $self->client;

	$client->POST(
		sprintf(
			'/subscriptions/%s/images/%s/sizes/%s.json',
			$subscription->id, $image_id, $size
		),
		$self->with_auth_params(
			format   => $format,
			metadata => encode_json($metadata),
		)
	);

	return WebService::Shutterstock::LicensedImage->new($client->process_response);
}

1;

__END__

=pod

=head1 NAME

WebService::Shutterstock::Customer - Class allowing API operations in the context of a specific customer

=head1 VERSION

version 0.002

=head1 SYNOPSIS

	my $customer = $shutterstock->auth("my-user" => "my-password");

	# retrieve list of lightboxes
	my $lightboxes = $customer->ligthboxes;

	# retrieve a specific lightbox for this user
	my $lightbox = $customer->lightbox(123);

	my $subscriptions = $customer->subscriptions;
	my $enhanced_subscription = $customer->subscription(license => 'enhanced');

	my $download_history = $customer->downloads;

	# license an image (if you only have a single active subscription)
	my $licensed_image = $customer->license_image(
		image_id => 59915404,
		size     => 'huge'
	);

	# license an image (if you have more than one active subscription)
	my $licensed_image = $customer->license_image(
		image_id     => 59915404,
		size         => 'huge',
		subscription => { license => 'standard' }
	);

=head1 DESCRIPTION

This class provides access to API operations (download history, lightbox interaction, subscriptions, etc) that require an authenticated
customer (via L<WebService::Shutterstock/"auth">).

=head1 METHODS

=head2 account_id

Retrieves the account ID for this account.

=head2 subscriptions

Returns an ArrayRef of L<WebService::Shutterstock::Subscription> objects for this customer account.

=head2 subscription

Convenience wrapper around the C<find_subscriptions> method that always
returns the first match (useful when you're matching on a field that is
unique like C<id> or C<license>).

	# find the (single) subscription providing an enhanced license
	my $media_digital_subscription = $customer->subscription(license => 'enhanced');

=head2 find_subscriptions

Retrieve a list of L<WebService::Shutterstock::Subscription> objects, based
on the criteria passed in to the method. Filter criteria should have
L<WebService::Shutterstock::Subscription> attribute names as keys with the value
to be matched as the value.  Subscriptions that match ALL the provided
criteria are returned as a list.  Some examples:

	# simple equality filters
	my @active_subscriptions = $customer->find_subscriptions( is_active => 1 );
	my @active_subscriptions = $customer->find_subscriptions( is_active => 1 );

	# regular expressions work too
	my @all_media_subscriptions = $customer->find_subscriptions( license => qr{^media} );

	# use an anonymous sub for more detailed filters (i.e. subscriptions expiring in the 
	my @soon_to_expire = $customer->find_subscriptions(
		is_active            => 1,
		unix_expiration_time => sub { shift < time + ( 60 * 60 * 24 * 30 ) }
	);

=head2 lightboxes($get_extended_info)

Returns an ArrayRef of L<WebService::Shutterstock::Lightbox> objects for this
customer acount.  By default, it gets only the lightbox information and
the list of image IDs in the lightbox.  If you would like to retrieve
more details about those images (specifically sizes and thumbnail URLs)
in a single HTTP request, just pass a true value as the only argument
to this method.

=head2 lightbox($id)

Returns a specific lightbox (as a L<WebService::Shutterstock::Lightbox> object)
for the given C<$id> (it must belong to this user).  If that lightbox
doesn't exist, C<undef> will be returned.  Unfortunately, Shutterstock's
API currently returns an HTTP status of C<500> on an unknown lightbox ID
(which could mask other error situations).

=head2 downloads

Retrieve the download history for this customer account.  You can
specify a C<page_number> argument if you prefer to retrieve a single
page of results (starting with page C<0>).  Or, you can fetch the
C<redownloadable_state> of a particular image:

	my $redownloadable_state = $customer->downloads(
		image_id => 11024440,
		field    => "redownloadable_state"
	);

The data returned will look something like this:

	[
		{
			image_id => 1,
			license  => 'standard',
			time     => '2012-11-01 14:16:08',
		},
		{
			image_id => 2,
			license  => 'premier',
			metadata => { purchase_order => 'XYZ', client => 'My Client' },
			time     => '2012-11-01 14:18:39',
		},
		# etc...
	]

=head2 license_image(image_id => $image_id, size => $size)

Licenses a specific image in the requested size.  Returns a
L<WebService::Shutterstock::LicensedImage> object.

If you have more than one active subscription, you will need to specify
which subscription you would like to use for licensing with a C<subscription>
argument.  You can pass in a L<WebService::Shutterstock::Subscription> object or
any criteria that can be passed to L</find_subscriptions> that will identify
a single subscription.  For instance:

	# by "license"
	my $licensed_image = $customer->license_image(
		image_id     => $image_id,
		size         => $size,
		subscription => { license => 'standard' }
	);

	# by "id"
	my $licensed_image = $customer->license_image(
		image_id     => $image_id,
		size         => $size,
		subscription => { id => 63746273 }
	);

	# or explicitly, with a subscription object
	my $enhanced = $customer->subscription( license => 'enhanced' );
	my $licensed_image = $customer->license_image(
		image_id     => $image_id,
		size         => $size,
		subscription => $enhanced
	);

=head1 AUTHOR

Brian Phillips <bphillips@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Brian Phillips and Shutterstock, Inc. (http://shutterstock.com).

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
