package AppUser::User::User;

use strict;
use warnings;

use Data::Dumper;

use lib '/app/tools/appuser/lib';
use AppUser::DB::Item::User;
use AppUser::User::UserAccess;
use AppUser::User::AccessLevel;
use AppUser::User::Address;
use AppUser::User::Token;
use AppUser::ForgotPW::Command::ForgotPW;

use lib '/app/tools/common/lib';
use Common::RSApp;
use Common::Assert;
use Common::DB::Item::Client;
use RSApache::RSWebApp;

use lib '/app/tools/rps/lib';
use Common::FormObject;
use Common::Email;
use base 'Common::FormObject';

sub _init {
    my ( $self, %args ) = @_;

    $self->SUPER::_init(%args);

    my %properties;

    if ( $args{_dbItem} ) {
        $self->_propertiesFromDBItem( \%properties, $args{_dbItem} );
    } elsif ( $args{userID} ) {
        $self->_propertiesFromDB( \%properties, $args{userID} );
    } elsif ( $args{email} ) {
        $self->_propertiesFromDB( \%properties, $args{email} );
    } else {

        # $self->_propertiesFromDefaults(\%properties);
    }

    $self->_initProperties( \%properties );
    $self->_initSubs( \%properties );

    return $self;
}

sub _propertiesFromDB {
    my ( $self, $hrProperties, $lookup ) = @_;
    my $dbItem;

    if ( $lookup =~ /^\d+$/ ) {
        $dbItem = AppUser::DB::Item::User->Lookup( user_id => $lookup );
    } else {
        $dbItem = AppUser::DB::Item::User->Lookup( email => $lookup );
    }

    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

sub _propertiesFromDBItem {
    my ( $self, $hrProperties, $dbItem ) = @_;

    # take values directly, don't use AUTOLOAD methods since $dbItem can be undefined. See RSD-1328.
    $hrProperties->{user_id}    = $dbItem->{user_id};
    $hrProperties->{email}      = $dbItem->{email};
    $hrProperties->{first_name} = $dbItem->{first_name};
    $hrProperties->{last_name}  = $dbItem->{last_name};
    $hrProperties->{address_id} = $dbItem->{address_id};
    $hrProperties->{phone1}     = $dbItem->{phone1};
    $hrProperties->{phone2}     = $dbItem->{phone2};
    $hrProperties->{phone3}     = $dbItem->{phone3};
    $hrProperties->{disabled}   = $dbItem->{disabled};
    $hrProperties->{mfa_type}   = $dbItem->{mfa_type};

    $hrProperties->{date_created}  = $dbItem->{date_created};
    $hrProperties->{date_modified} = $dbItem->{date_modified};

    return 1;
}

sub _initProperties {
    my ( $self, $props ) = @_;

    $self->{UserID} = Common::FormObject::Scalar->new( value => $props->{user_id}, readOnly => 1 );
    $self->{Email} = Common::FormObject::Scalar::EmailAddress->new( value => $props->{email}, required => 1 );
    $self->{FirstName} = Common::FormObject::Scalar::String->new( value => $props->{first_name}, required => 1 );
    $self->{LastName}  = Common::FormObject::Scalar::String->new( value => $props->{last_name},  required => 1 );
    $self->{AddressID} = Common::FormObject::Scalar->new( value => $props->{address_id} );
    $self->{Phone1} = Common::FormObject::Scalar::PhoneNumber->new( value => $props->{phone1} );
    $self->{Phone2} = Common::FormObject::Scalar::PhoneNumber->new( value => $props->{phone2} );
    $self->{Phone3} = Common::FormObject::Scalar::PhoneNumber->new( value => $props->{phone3} );
    $self->{Disabled} = Common::FormObject::Scalar::Boolean->new( value => $props->{disabled} );
    $self->{MFAType} = Common::FormObject::Scalar->new( value => $props->{mfa_type} );

    $self->{DateCreated}  = Common::FormObject::Scalar::DateTime->new( value => $props->{date_created},  readOnly => 1 );
    $self->{DateModified} = Common::FormObject::Scalar::DateTime->new( value => $props->{date_modified}, readOnly => 1 );

    # $self->{CreatedBy}			= Common::FormObject::Scalar::UserName->new(value => $props->{created_by}, readOnly => 1);
    # $self->{ModifiedBy}			= Common::FormObject::Scalar::DateTime->new(value => $props->{date_created}, readOnly => 1);

    my $accessLevel;
    my $labelID;
    my $imprintID;
    my $publisherID;
    my $clientID = Common::RSApp::GetClientID();
    if ( $props->{user_id} ) {

        # Determine access level.   Note that 'super' users will have '0' in their client_id column in the
        # user_access table.
        #
        my $userAccessList = AppUser::DB::Item::UserAccess->GetByUserID( $props->{user_id} );
        while ( my $userAccess = $userAccessList->next() ) {
            if ( $userAccess->client_id == $clientID || $userAccess->client_id == 0 ) {
                $accessLevel         = $userAccess->access_level;
                $labelID             = $userAccess->label_id;
                $imprintID           = $userAccess->imprint_id;
                $publisherID         = $userAccess->publisher_id;
                $self->{_userAccess} = $userAccess;
                last;
            }
        }
    }

    if ($clientID) {
        my $clientData = Common::DB::Item::Client->Lookup( client_id => $clientID );
        $self->{ClientNameClean} = Common::FormObject::Scalar::String->new( value => $clientData->client_name_clean, readOnly => 1 );
        $self->{ClientLogo} = Common::FormObject::Scalar::String->new( value => $clientData->client_logo, readOnly => 1 );
    }
    $self->{AccessLevel} = Common::FormObject::Scalar->new( value => $accessLevel, readOnly => 1 );
    $self->{ClientID} = Common::FormObject::Scalar->new( value => $clientID );

    #	$self->{LabelID} = Common::FormObject::Scalar::Integer->new(value => $labelID);

    if ( $props->{user_id} ) {
        if ( $self->{_userAccess} ) {
            $self->{UserAccess} = AppUser::User::UserAccess->new( _dbItem => $self->{_userAccess} );
            $self->{_userAccess} = undef;    # cleanup
        } else {
            $self->{UserAccess} = AppUser::User::UserAccess->new( userID => $props->{user_id} );
        }
        $self->{Address} = AppUser::User::Address->new( addressID => $props->{address_id} );
    } else {
        $self->{UserAccess} = AppUser::User::UserAccess->new();
        $self->{Address}    = AppUser::User::Address->new();
    }
}

sub _initSubs {
    my ( $self, $props ) = @_;

    # subclasses
    #
    #	if($self->loadSubs())
    #	{
    #		if($props->{user_id})
    #		{
    #			if($self->{_userAccess})
    #			{
    #				$self->{UserAccess} = AppUser::User::UserAccess->new(_dbItem => $self->{_userAccess});
    #				$self->{_userAccess} = undef; # cleanup
    #			}
    #			else
    #			{
    #				$self->{UserAccess} = AppUser::User::UserAccess->new(userID => $props->{user_id});
    #			}
    #			$self->{Address} = AppUser::User::Address->new(addressID => $props->{address_id});
    #		}
    #		else
    #		{
    #			$self->{UserAccess} = AppUser::User::UserAccess->new();
    #			$self->{Address} = AppUser::User::Address->new();
    #		}
    #	}
}

# This will default to the first label in the list
#
sub LabelID {
    my ($self) = @_;

    my $allLabels = $self->getLabelIDs();

    return undef unless $allLabels;
    return $allLabels->[0];
}

sub getLabelIDs {
    my ($self) = @_;
    return undef unless $self->{UserAccess};

    # Only Label users have any business having a list of labels.
    #
    return undef unless $self->AccessLevel() == AppUser::DB::Item::AccessLevel::kLabelReport;

    return $self->{UserAccess}->getLabelIDs();
}

# This will default to the first imprint in the list
#
sub ImprintID {
    my ($self) = @_;

    my $allImprints = $self->getImprintIDs();

    return undef unless $allImprints;
    return $allImprints->[0];
}

sub getImprintIDs {
    my ($self) = @_;
    return undef unless $self->{UserAccess};

    # Only Imprint users have any business having a list of imprints.
    # Actually, Publisher users will now have a list of imprints too.
    return undef
      unless ( $self->AccessLevel() == AppUser::DB::Item::AccessLevel::kImprintView
        || $self->AccessLevel() == AppUser::DB::Item::AccessLevel::kPublisherView );

    return $self->{UserAccess}->getImprintIDs();
}

# This will default to the first publisher in the list
#
sub PublisherID {
    my ($self) = @_;

    my $allPublishers = $self->getPublisherIDs();

    return undef unless $allPublishers;
    return $allPublishers->[0];
}

sub getPublisherIDs {
    my ($self) = @_;
    return undef unless $self->{UserAccess};

    # Only Publisher users have any business having a list of publishers.
    #
    return undef unless $self->AccessLevel() == AppUser::DB::Item::AccessLevel::kPublisherView;

    return $self->{UserAccess}->getPublisherIDs();
}

sub validate {
    my ($self) = @_;

    my $valid = $self->SUPER::validate();

    if ( !$self->Email() ) {
        $self->{Email}->setError(Common::FormObject::kErrFieldBlank);
        $valid = 0;
    } else {

        # is this email in use?
        #
        my $tmpUser = AppUser::DB::Item::User->Lookup( email => $self->Email() );

        # if this email is in use then we need to verify
        # it's ok to be using it here
        #
        if ( $tmpUser && $tmpUser->user_id ) {

            # is this a new user trying to use this email?
            # OR
            # is the owner of this email NOT the same as the user we're updating?
            #
            if ( !$self->UserID() || ( $self->UserID() != $tmpUser->user_id ) ) {

                # sorry, this email is in use
                #
                $self->{Email}->setError(Common::FormObject::kErrEmailNotAvailable);
                $valid = 0;
            }
        }
    }

    my $currentUser = AppUser::User::User->new( userID => Common::RSApp->GetActiveUserID() );

    return $valid;
}

sub save {
    my ($self) = @_;

    # -------------------------------
    # Save myself FIRST
    # -------------------------------
    #
    my $dbItem;
    my $new = 0;
    if ( $self->UserID() ) {
        $dbItem = AppUser::DB::Item::User->Lookup( user_id => $self->UserID() );
    } else {
        $dbItem = AppUser::DB::Item::User->Create();
        $new    = 1;
    }

    $dbItem->email( $self->Email() );
    $dbItem->first_name( $self->FirstName() );
    $dbItem->last_name( $self->LastName() );

    # $dbItem->address_id($addressID));
    $dbItem->phone1( $self->Phone1() );
    $dbItem->phone2( $self->Phone2() );
    $dbItem->phone3( $self->Phone3() );
    $dbItem->disabled( $self->Disabled() );

    $dbItem->save();

    # -------------------------------
    # Save sub objects
    # -------------------------------
    #
    $self->{UserAccess}->UserID( $dbItem->user_id );
    $self->{UserAccess}->save();

    $self->{Address}->UserID( $dbItem->user_id );
    $self->{Address}->save();

    if ($new) {
        $dbItem->address_id( $self->{Address}->AddressID() );
        $dbItem->save();
    }

    # reload object
    #
    $self->_init( _dbItem => $dbItem );
}

sub GetClientList {
    my ($self) = @_;
    my @list;

    my $userAccessColl = AppUser::DB::Item::UserAccess->GetByUserID( $self->UserID );
    my $clientColl     = Common::DB::Item::Client->GetAll();

    my %clientObjs;
    while ( $clientColl->hasNext ) {
        my $obj = $clientColl->next;
        $clientObjs{ $obj->client_id } = $obj;
    }

    # if client_id is 0 or has multiple clients, return undef
    # else return the client_id
    #
    if ($userAccessColl) {
        if ( $userAccessColl->size > 1 ) {
            while ( $userAccessColl->hasNext ) {
                my $userAccess = $userAccessColl->next;
                if ( $clientObjs{ $userAccess->client_id } ) {
                    push @list, $clientObjs{ $userAccess->client_id };
                }
            }
        } else {
            my $userAccess = $userAccessColl->next;
            if ( $userAccess->client_id == 0 ) {
                @list = values %clientObjs;
            }
        }
    }

    return \@list;
}

sub SendNewUserEmail {
    print STDERR "SendNewUserEmail: start...\n";
    my $self      = shift;
    my $recipient = $self->Email();
    my $hostname  = RSApache::RSWebApp::GetHttpHost();

    my $tokenObj = AppUser::User::Token->new( email => $self->Email() );
    my %params = (
        Form_Email => $recipient,
        Form_Token => $tokenObj->GetTimedToken(),
        'new'      => 1,                            # this is for the template
    );
    my $cmd              = AppUser::ForgotPW::Command::ForgotPW->new(%params);
    my $uri              = $cmd->getRedirect();
    my $setupPasswordURL = "https://" . $hostname . $uri;

    my $body;
    if ( AppUser::User::UserAccess::kClientUser() == $self->AccessLevel() ) {
        $body = qq(
Welcome to RoyaltyShare!

An account has been created for you at RoyaltyShare.  This account enables you to browse reports detailing sales from your digital music sources.

To initiate your account and establish your secure password, simply click on the URL below and follow the instructions.

	$setupPasswordURL

Once your account is established, you can log in and begin accessing your sales data.  If you experience any problems with this process, please contact your account manager.

Sincerely,

RoyaltyShare Support
);
    }

    # elsif($self->AccessLevel == AppUser::User::UserAccess::kClientAdmin() ||
    # $self->AccessLevel == AppUser::User::UserAccess::kClientRep())
    else {
        $body = qq(
Welcome to RoyaltyShare!

An account has been created for you at RoyaltyShare.

To initiate your account and establish your secure password, simply click on the URL below and follow the instructions.

	$setupPasswordURL

Once your account is established, you can log in and begin accessing the system.  If you experience any problems with this process, please contact your account manager.

Sincerely,

RoyaltyShare Support
);
    }

    # else
    # {
    # royalty share users don't get the email.
    # return 1;
    # }

    my $from = 'do-not-reply@royaltyshare.com';
    my $to = $recipient;
    my $subject = "New RoyaltyShare Account";

    Common::Email->SendAWS(
        to      => $to,
        from    => $from,
        subject => $subject,
        body    => $body
    );
}

###
1;    # Play nicely.
###
