<?php
namespace models;

/**
 * User model class
 * @version 3.0
 */
class User extends \ActiveRecord implements IUser {
    
    const INACTIVE = 0;
    const ACTIVE = 1;

    /**
     * @var array roles Roles
     * @access protected
     */
    protected $roles = null;
    
    /**
     * @var array permissions Permissions
     * @access protected
     */
    protected $permissions = null;

    protected function validate() {
        $i18n = \IoC::resolve( 'i18n' );
        $this->validateNotEmpty( 'username', $i18n->__( 'username_cannot_be_empty' ) );
        $this->validateMinLength( 'username', 3, $i18n->__( 'too_short_username', 3 ) );
        $this->validateMaxLength( 'username', 100, $i18n->__( 'too_long_username', 100 ) );
        if ( !empty( $this->password ) ) {
            $this->validateMinLength( 'password', 5, $i18n->__( 'too_short_password', 5 ) );
            $this->validateMaxLength( 'password', 50, $i18n->__( 'too_long_password', 50 ) );
            $this->validateEqual( 'password', $this->password_confirmation, $i18n->__( 'passwords_do_not_match' ) );
        }
        $this->validateNotEmpty( 'email', $i18n->__( 'email_cannot_be_empty' ) );
        $this->validateMaxLength( 'email', 255, $i18n->__( 'too_long_email', 255 ) );
        $this->validateEmail( 'email', $i18n->__( 'invalid_email' ) );
    }

    protected function validateOnInsert() {
        $i18n = \IoC::resolve( 'i18n' );
        $this->validateNotEmpty( 'password', $i18n->__( 'password_cannot_be_empty' ) );
        $this->validateUnique( 'username', $i18n->__( 'username_already_taken' ) );
        $this->validateUnique( 'email', $i18n->__( 'email_already_in_use' ) );
    }

    protected function validateOnUpdate() {
        $i18n = \IoC::resolve( 'i18n' );
        if ( $this->isAttributeChanged( 'username' ) ) {
            $this->validateUnique( 'username', $i18n->__( 'username_already_taken' ) );
        }
        if ( $this->isAttributeChanged( 'email' ) ) {
            $this->validateUnique( 'email', $i18n->__( 'email_already_in_use' ) );
        }
    }
    
    protected function afterFind() {
        if ( isset( $this->preferences ) ) {
            $this->preferences = JSONHandler::decode( $this->preferences, true );
        }
    }

    protected function beforeSave() {
        if ( !empty( $this->password ) ) {
            $this->password = trim( $this->password );
            $this->encrypted_password = password_hash( $this->password, PASSWORD_DEFAULT );
            unset( $this->password );
            unset( $this->password_confirmation );
        }
        $this->email = trim( $this->email );
        $this->email = strtolower( $this->email );
        
        if ( isset( $this->preferences ) ) {
            $this->preferences = JSONHandler::encode( $this->preferences );
        }
    }

    // protected function beforeInsert() {
    //     $this->activation_Key = bin2hex( random_bytes ( 20 ) );
    //     $this->status = self::INACTIVE;
    // }

    /**
     * Retrieve a user by username
     * @param string username Username
     * @return User
     * @access public
     */
    public static function findByUsername( $username ) {
        return self::findOne( ['username' => $username, 'status' => self::ACTIVE] );
    }

    /**
     * Retrieve a user by e-mail
     * @param string email E-mail
     * @return User
     * @access public
     */
    public static function findByEmail( $email ) {
        return self::findOne( ['email' => $email, 'status' => self::ACTIVE] );
    }

    /**
     * Retrieve a user by username or e-mail
     * @param string $usernameOrEmail Username or e-mail
     * @return User
     * @access public
     */
    public static function findByUsernameOrEmail( $usernameOrEmail ) {
        $record = self::findByUsername( $usernameOrEmail );
        if ( !$record ) {
            $record = self::findByEmail( $usernameOrEmail );
        }
        return $record;
    }

    public function authenticate( $password ) {
        return password_verify( $password, $this->encrypted_password );
    }

    /**
     * @return boolean
     */
    public function isAuthenticated() {
        return true;
    }

    /**
     * @return string
     */
    public function getName() {
        return $this->username;
    }
    
    public function hasRole( $name ) {
        return in_array( $name, array_column( $this->getRoles(), 'name' ) );
    }
    
    public function getRoles() {
        if ( empty( $this->roles ) ) {
            $this->roles = Role::findMany( ['[<]user_role' => 'role_id'], ['name'], ['user_id' => $this->user_id] );
        }
        return $this->roles;
    }

    public function getPermissions() {
        if ( empty( $this->permissions ) ) {
            $this->permissions = Permission::findMany( ['[<]role_permission' => 'permission_id', '[<]user_role' => 'role_id'], '*', ['user_id' => $this->user_id] );
        }
        return $this->permissions;
    }

    /**
     * Checks if the  user has the specified permission
     * @param string name
     * @return boolean
     * @access public
     */
    public function hasPermission( $name ) {
        return in_array( $name, array_column( $this->getPermissions(), 'name' ) );
    }

    public function __toString() {
        return $this->username;
    }

}

?>
