package Foorum::Controller::Profile;

use strict;
use warnings;
our $VERSION = '1.001000';
use parent 'Catalyst::Controller';
use Foorum::XUtils qw/theschwartz/;
use Digest ();
use Locale::Country::Multilingual;
use vars qw/$lcm/;
$lcm = Locale::Country::Multilingual->new();

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

    return $c->res->redirect('/login') unless ( $c->user_exists );

    $c->stash->{template} = 'user/profile/edit.html';

    # get all countries code
    $lcm->set_lang( $c->stash->{lang} );
    my @codes = $lcm->all_country_codes();
    my %countries;
    foreach (@codes) {
        $countries{$_} = $lcm->code2country($_);
    }
    $c->stash->{countries} = \%countries;

    unless ( $c->req->method eq 'POST' ) {
        my $birthday = $c->user->{details}->{birthday};
        if (    $birthday
            and $birthday
            and $birthday =~ /^(\d+)\-(\d+)\-(\d+)$/ ) {
            $c->stash(
                {   year  => $1,
                    month => $2,
                    day   => $3,
                }
            );
        }
        $c->stash->{user_details} = $c->user->{details};
        return;
    }

    my $birthday
        = $c->req->param('year') . '-'
        . $c->req->param('month') . '-'
        . $c->req->param('day');
    my ( @extra_valid, @extra_insert );
    if ( length($birthday) > 2 ) {    # is not --
        @extra_valid
            = ( { birthday => [ 'year', 'month', 'day' ] } => ['DATE'] );
        @extra_insert = ( birthday => $birthday );
    }

    # be compatible with Yahoo! ID and email
    foreach my $param ( 'gtalk', 'yahoo', 'skype' ) {
        if ( $c->req->param($param) =~ /^(\w+)\@/ ) {
            $c->req->param( $param, $1 );    # only need the username before @
        }
    }

    $c->form(
        gender => [ [ 'REGEX', qr/^(M|F)?$/ ] ],
        lang   => [ [ 'REGEX', qr/^\w{2}$/ ] ],
        @extra_valid,
        homepage => ['HTTP_URL'],
        nickname => [ qw/NOT_BLANK/, [qw/LENGTH 4 20/] ],
        'qq'     => [ [ 'REGEX', qr/^\d{6,14}$/ ] ],
        msn => [ qw/EMAIL_LOOSE/, [qw/LENGTH 5 64/] ],
        gtalk   => [ [ 'REGEX', qr/^\w{2,64}$/ ] ],
        yahoo   => [ [ 'REGEX', qr/^\w{2,64}$/ ] ],
        skype   => [ [ 'REGEX', qr/^\w{2,64}$/ ] ],
        country => [ [ 'REGEX', qr/^\w{2}$/ ] ],
    );
    return if ( $c->form->has_error );

    # validate country
    unless ( $lcm->code2country( $c->req->param('country') ) ) {
        $c->req->param( 'country', '' );
    }
    $c->model('DBIC::User')->update_user(
        $c->user,
        {   nickname => $c->req->param('nickname') || $c->user->username,
            gender   => $c->req->param('gender')   || 'NA',
            lang => $c->req->param('lang') || $c->config->{default_lang},
            country => $c->req->param('country') || '',
        }
    );

    $c->model('DBIC::UserDetails')->update_or_create(
        {   user_id  => $c->user->user_id,
            homepage => $c->req->param('homepage') || '',
            'qq'     => $c->req->param('qq') || '',
            msn      => $c->req->param('msn') || '',
            gtalk    => $c->req->param('gtalk') || '',
            yahoo    => $c->req->param('yahoo') || '',
            skype    => $c->req->param('skype') || '',
            @extra_insert,
        }
    );

    # clear user cache too
    $c->model('DBIC::User')->delete_cache_by_user( $c->user );

    $c->res->redirect( '/u/' . $c->user->username );
}

sub change_password : Local {
    my ( $self, $c, $username, $security_code ) = @_;

    my $password = $c->req->param('password');
    $c->stash->{template} = 'user/profile/change_password.html';

    my $user;

    # the user input old password
    # or the user click from forget_password email
    # CAN change password
    my $can_change_password = 0;
    if ( $username and $security_code ) {

        # check if that's mataches.
        $user = $c->model('DBIC::User')->get( { username => $username } );
        if ($user) {
            my $security_code2 = $c->model('DBIC::SecurityCode')
                ->get( 'forget_password', $user->{user_id} );
            if ( $security_code2 and $security_code2 eq $security_code ) {
                $can_change_password = 1;
                $c->stash->{use_security_code} = 1;
            }
        }
        $c->stash->{user} = $user;
    }
    unless ($can_change_password) {
        return $c->res->redirect('/login') unless ( $c->user_exists );
        $user = $c->user;
        $c->stash->{user} = $user;

        # check the password typed in is correct
        if ($password) {
            my $d = Digest->new(
                $c->config->{authentication}->{password_hash_type} );
            $d->add($password);
            my $computed = $d->digest;
            if ( $computed ne $c->user->{password} ) {
                $c->set_invalid_form( password => 'WRONG_PASSWORD' );
                $c->stash->{user} = $user;
                return;
            }
            $can_change_password = 1;
        }
    }

    return unless ($can_change_password);

    # execute validation.
    $c->form(
        new_password => [ qw/NOT_BLANK/, [qw/LENGTH 6 20/] ],
        { passwords => [ 'new_password', 'confirm_password' ] } =>
            ['DUPLICATION'],
    );
    return if ( $c->form->has_error );

    # encrypted the new password
    my $new_password = $c->req->param('new_password');
    my $d = Digest->new( $c->config->{authentication}->{password_hash_type} );
    $d->reset;
    $d->add($new_password);
    my $new_computed = $d->digest;

    $c->model('DBIC::User')
        ->update_user( $user, { password => $new_computed } );

    # delete so that can't use again
    if ( $c->stash->{use_security_code} ) {
        $c->model('DBIC::SecurityCode')
            ->remove( 'forget_password', $user->{user_id} );
    }

    $c->res->redirect('/profile/edit?st=101');
}

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

    $c->stash->{template} = 'user/profile/forget_password.html';
    return unless ( $c->req->method eq 'POST' );

    my $username = $c->req->param('username');
    my $email    = $c->req->param('email');

    my $user;
    if ($username) {
        $user = $c->model('DBIC::User')->get( { username => $username } );
        return $c->stash->{ERROR_NOT_SUCH_USER} = 1 unless ($user);
        $email = $user->{email};
    } elsif ($email) {
        $user = $c->model('DBIC::User')->get( { email => $email } );
        return $c->stash->{ERROR_NOT_SUCH_EMAIL} = 1 unless ($user);
        $username = $user->{username};
    } else {
        return;
    }

    # create a security code
    # URL contains the security_code can change his password later
    my $security_code = $c->model('DBIC::SecurityCode')
        ->get_or_create( 'forget_password', $user->{user_id} );

    # send email
    $c->model('DBIC::ScheduledEmail')->create_email(
        {   template => 'forget_password',
            to       => $email,
            lang     => $c->stash->{lang},
            stash    => {
                username      => $username,
                security_code => $security_code,
                IP            => $c->req->address,
            }
        }
    );

    $c->res->redirect('/?st=102');
}

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

    return $c->res->redirect('/login') unless ( $c->user_exists );

    $c->stash->{template} = 'user/profile/change_email.html';

    return unless ( $c->req->method eq 'POST' );

    # check the password typed in is correct
    my $password = $c->req->param('password');
    my $d = Digest->new( $c->config->{authentication}->{password_hash_type} );
    $d->add($password);
    my $computed = $d->digest;
    if ( $computed ne $c->user->{password} ) {
        $c->set_invalid_form( password => 'WRONG_PASSWORD' );
        return;
    }

    # validation
    my $email = $c->req->param('email');
    if ( $email eq $c->user->email ) {
        return $c->set_invalid_form( email => 'EMAIL_DUPLICATION' );
    }
    my $err = $c->model('DBIC::User')->validate_email($email);
    if ($err) {
        return $c->set_invalid_form( email => $err );
    }

    $c->model('DBIC::User')->update_user( $c->user, { email => $email } );
    $c->res->redirect('/profile/edit');
}

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

    return $c->res->redirect('/login') unless ( $c->user_exists );

    $c->stash->{template} = 'user/profile/change_username.html';

    return unless ( $c->req->method eq 'POST' );

    # check the password typed in is correct
    my $password = $c->req->param('password');
    my $d = Digest->new( $c->config->{authentication}->{password_hash_type} );
    $d->add($password);
    my $computed = $d->digest;
    if ( $computed ne $c->user->{password} ) {
        $c->set_invalid_form( password => 'WRONG_PASSWORD' );
        return;
    }

    # execute validation.
    $c->form(
        new_username => [qw/NOT_BLANK/],
        { usernames => [ 'new_username', 'confirm_username' ] } =>
            ['DUPLICATION'],
    );
    return if ( $c->form->has_error );

    my $new_username = $c->req->param('new_username');
    my $err = $c->model('DBIC::User')->validate_username($new_username);
    if ($err) {
        $c->set_invalid_form( new_username => $err );
        return;
    }

    $c->model('DBIC::User')
        ->update_user( $c->user, { username => $new_username, } );
    $c->session->{__user} = $new_username;

    $c->res->redirect("/u/$new_username");
}

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

    return $c->res->redirect('/login') unless ( $c->user_exists );

    $c->stash->{template} = 'user/profile/profile_photo.html';

    return unless ( $c->req->method eq 'POST' );

    my $new_upload = $c->req->upload('upload');
    my $old_upload_id
        = ( $c->user->{profile_photo}->{type} eq 'upload' )
        ? $c->user->{profile_photo}->{value}
        : 0;
    my $new_upload_id = $old_upload_id;
    if ( ( $c->req->param('attachment_action') eq 'delete' ) or $new_upload )
    {

        # delete old upload
        if ($old_upload_id) {
            $c->model('DBIC::Upload')
                ->remove_by_upload( $c->user->{profile_photo}->{upload} );
            $new_upload_id = 0;
        }

        # add new upload
        if ($new_upload) {
            $new_upload_id = $c->model('DBIC::Upload')
                ->add_file( $new_upload, { user_id => $c->user->user_id } );
            unless ( $new_upload_id =~ /^\d+$/ ) {
                return $c->set_invalid_form( upload => $new_upload_id );
            }

            my $client = theschwartz();
            $client->insert(
                'Foorum::TheSchwartz::Worker::ResizeProfilePhoto',
                $new_upload_id );
        }
    }

    $c->model('DBIC')->resultset('UserProfilePhoto')
        ->search( { user_id => $c->user->{user_id} } )->delete;
    $c->model('DBIC')->resultset('UserProfilePhoto')->create(
        {   user_id => $c->user->{user_id},
            type    => 'upload',
            value   => $new_upload_id,
            width   => 0,
            height  => 0,
            time    => time(),
        }
    );

    $c->model('DBIC::User')->delete_cache_by_user( $c->user );

    $c->res->redirect( '/u/' . $c->user->{username} );
}

1;
__END__

=pod

=head1 AUTHOR

Fayland Lam <fayland at gmail.com>

=cut