<?php
/**
 * Copyright 2016 David Vivier on behalf of Smartic.ca
 * 
 * This file is part of the Smarticops Package
 * 
 * License : MIT
 * 
 * @author David Vivier
 */

namespace Dvivier\Smarticops;

use Log;

use Illuminate\Http\Request;

use Auth;
use Dvivier\Smarticops\Permission;
use Dvivier\Smarticops\User;
use Dvivier\Smarticops\Role;

use DB;

/** The features of the Smarticops Facade.
 *  Permissions features are managed in Models, this class manages logging features.
 * 
 *  Each method logs a specific action, accepts parameters related to this action, and a boolean representing the success or failure of the operation.
 *  Each specific log method uses the generic log() method, which will add info
 * 
 *  It is named SmarticopsClass to differentiate from Facade\Smarticops to avoid confusion
 * 
 * @see SmarticopsClass::log()  log()
 * 
 * @author David Vivier
 */
class SmarticopsClass {
    
    public function test() {
        Log::info('Smarticops-Test', ['id' => Auth::user()->id ]);
    }
    
    /**
     *  The generic log() method
     * 
     * Saves each log information in the daily log file AND in the `logs` table of the database.
     * For each logs it adds the id of the user that is currently logged in.
     * 
     * @param  string  $txt  The text to log
     * @param  array  $context  array of data to add to the text
     * @param  string  $type  The type of log
     * 
     * @see https://github.com/Seldaek/monolog  Monolog library
     */
    public function log($txt, $context = [], $type = 'info') {
        
        $log_id = DB::table('logs')->insertGetId([
                                    'timestamp'     => date("Y-m-d H:i:s"),
                                    'type'          => $type,
                                    'user_id'       => Auth::check() ? Auth::user()->id : 0,
                                    'event'         => $txt,
                                    ]);
                                
        Log::info($txt, array_merge(
                                    [ 'auth_user_id' => Auth::check() ? Auth::user()->id : 0,
                                      'log_id'       => $log_id,
                                      ],
                                        $context
                                    ));
    }
    
    
    public function logError($txt, $context = [], $type = 'error') {
        $log_id = DB::table('logs')->insertGetId([
                            'timestamp'     => date("Y-m-d H:i:s"),
                            'type'          => $type,
                            'user_id'       => Auth::check() ? Auth::user()->id : 0,
                            'event'         => $txt,
                            ]);
                            
        Log::error($txt, array_merge(
                                    [ 'auth_user_id' => Auth::check() ? Auth::user()->id : 0,
                                      'log_id'       => $log_id,
                                        ],
                                        $context
                                    ));
    }
    
    /// AUTH
    
    public function logAttempt($email) {
        self::log('Login attempt for email "'.$email.'"');
    }
    
    public function logLogin(User $user, $success = true, $remember = false) {
        self::log('User "'.$user->fullName().'" logged in succesfully.',[   
                        'user_id' => $user->id,
                        'user_first_name' => $user->first_name,
                        'user_last_name'    => $user->last_name,
                        'user_email'        => $user->email,
                        'remember'          => $remember,
                        ]);
    }
    
    public function logLogout(User $user) {
        self::log('User "'.$user->fullName().'" logged out.', [
                        'user_id' => $user->id,
                        'user_first_name' => $user->first_name,
                        'user_last_name'    => $user->last_name,
                        'user_email'        => $user->email,
                        ]);
    }
    
    public function logLockout($email) {
        self::log('Lockout ! Too many attemps for email "'.$email.'"');
    }
    
    
    /// PASSWORDS
    
    public function logPasswordResetRequest(Request $request, $res = true) {


        if ($res) {
            $token = DB::table('password_resets')->select('token')->where('email', $request->email)->first()->token;
            self::log('Password reset token sent for email "'.$request->email.'"', [
                                                                            'ip' => $request->ip(),
                                                                            'token' => $token,
                                                                            ]);
        }
        else {
            self::logError('Password reset failed for email "'.$request->email.'"', [
                                                                            'ip' => $request->ip(),
                                                                            ]);
        }
    }
    
    
    public function logPasswordResetClicked(Request $request, $token) {
        
        $email = $request->email;
        self::log('accessed password reset form', [
                                                    'token' => $token,
                                                    'email' => $email,
                                                    'ip'    => $request->ip(),
                                                    ]);
        
    }
    
    public function logPasswordReset(Request $request, $res = true) {
        $email = $request->email;
        $user = User::where('email', $email)->first();
        
        if ($res) {
            self::log('Successfully reset password for email "'.$email.
                      '" corresponding to User "'.$user->fullName().'"', [
                                                                        'user_id' => $user->id,
                                                                        'user_email' => $user->email,
                                                                        'ip' => $request->ip(),
                                                                        ]);
        }
        else {
            self::log('Failed resetting password for email "'.$email.
                      '" corresponding to User "'.$user->fullName().'"', [
                                                                        'user_id' => $user->id,
                                                                        'user_email' => $user->email,
                                                                        'ip' => $request->ip(),
                                                                        ]);
        }
    }
    
    
    
    
    /// USERS
    
    public function logUserCreated(User $user, $res = true, $context = []) {
        
        if ($user === null) {
            return;
        }

        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' created User "'.$user->fullName().'" - ', array_merge([ 
                                                                                'user_id' => $user->id,
                                                                                'first_name'          => $user->first_name,
                                                                                'last_name'   => $user->last_name,
                                                                                'email'         => $user->email,
                                                                                'uuid'          => $user->uuid,
                                                                                ],
                                                                                $context));
        }
        else {
            self::logError($auth_name.' failed to create user - ', $context);
            
        }
    }
    
    
    public function logUserUpdated(User $new, User $old, $res = true) {
        
        if ($new === null) {
            return;
        }

        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' updated User "'.$new->fullName().
                            '" - Before : {id:'.$old->id.', first_name:"'.$old->first_name.'", last_name:"'.$old->last_name.'", email:"'.$old->email.
                             '"} - After : {id:'.$new->id.', first_name:"'.$new->first_name.'", last_name:"'.$new->last_name.'", email:"'.$new->email.
                             '"}', [
                                    'uuid'      => $old->uuid,
                                    ]);
        }
        else {
            self::logError($auth_name.' failed to update User "'.$old->fullName().'" - ', [
                                                                                        'user_id' => $old->id,
                                                                                        'first_name'          => $old->last_name,
                                                                                        'last_name'   => $old->last_name,
                                                                                        'email'         => $old->email,
                                                                                        'uuid'      => $user->uuid,
                                                                                        ]);
        }
    }
    
    public function logUserDeleted(User $user, $res = true) {

        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' deleted User "'.$user->fullName().'" - ',
                                    [
                                        'user_id'    => $user->id,
                                        'first_name'  => $user->code,
                                        'last_name' =>  $user->last_name,
                                        'email'   => $user->email,
                                        'uuid'      => $user->uuid,
                                        ]);
        }
        else {
            self::logError($auth_name.' failed to delete User "'.$user->fullName().'" - ', [
                                                                                        'user_id' => $user->id,
                                                                                        'first_name'  => $user->first_name,
                                                                                        'last_name'   => $user->last_name,
                                                                                        'email'     => $user->email,
                                                                                        'uuid'      => $user->uuid,
                                                                                    ]);
        }
    }
    
    
    public function logAssignRole(User $user, Role $role, $res = true) {
        
        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' assigned Role "'.$role->name.'" for User "'.$user->fullName().'" ');
        }
        else {
            self::logError($auth_name.' failed assigning Role "'.$role->name.'" for User "'.$user->fullName().'" ', [
                                                                                                                'user_id'   => $user->id,
                                                                                                                'role_id'   => $role->id,
                                                                                                                ]);
        }
    }
    
    public function logRevokeRole(User $user, Role $role, $res = true) {
        
        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' revoked Role "'.$role->name.'" for User "'.$user->fullName().'" ');
        }
        else {
            self::logError($auth_name.' failed revoking Role "'.$role->name.'" for User "'.$user->fullName().'" ');
        }
    }
    
    
    
    //  PERMISSIONS
    
    public function logPermissionGivenToUser(Permission $permission, User $user, $value, $res = true) {
        
        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' gave Permission "'.$permission->code.'" to User "'.$user->fullName().'" ', [
                                                                                                                'user_id'               => $user->id,
                                                                                                                'user_first_name'       => $user->first_name,
                                                                                                                'user_last_name'        => $user->last_name,
                                                                                                                'user_email'            => $user->email,
                                                                                                                'permission_id'         => $permission->id,
                                                                                                                'permission_code'       => $permission->code,
                                                                                                                'permission_description' => $permission->description,
                                                                                                                'permission_value'      => $value,
                                                                                                                ]);
        }
        else {
            self::logError($auth_name.' failed giving Permission "'.$permission->code.'" to User "'.$user->fullName().'" ', [
                                                                                                                        'user_id'               => $user->id,
                                                                                                                        'user_first_name'       => $user->first_name,
                                                                                                                        'user_last_name'        => $user->last_name,
                                                                                                                        'user_email'            => $user->email,
                                                                                                                        'permission_id'         => $permission->id,
                                                                                                                        'permission_code'       => $permission->code,
                                                                                                                        'permission_description' => $permission->description,
                                                                                                                        'permission_value'      => $value,
                                                                                                                        
                                                                                                                        ]);
        }
    }
    

    public function logPermissionRemovedFromUser(Permission $permission, User $user, $res = true) {
        
        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' removed Permission "'.$permission->code.'" from User "'.$user->fullName().'" ', [
                                                                                                                'user_id'               => $user->id,
                                                                                                                'user_first_name'       => $user->first_name,
                                                                                                                'user_last_name'        => $user->last_name,
                                                                                                                'user_email'            => $user->email,
                                                                                                                'permission_id'         => $permission->id,
                                                                                                                'permission_code'       => $permission->code,
                                                                                                                'permission_description' => $permission->description,
                                                                                                                ]);
        }
        else {
            self::logError($auth_name.' failed removing Permission "'.$permission->code.'" from User "'.$user->fullName().'" ', [
                                                                                                                        'user_id'               => $user->id,
                                                                                                                        'user_first_name'       => $user->first_name,
                                                                                                                        'user_last_name'        => $user->last_name,
                                                                                                                        'user_email'            => $user->email,
                                                                                                                        'permission_id'         => $permission->id,
                                                                                                                        'permission_code'       => $permission->code,
                                                                                                                        'permission_description' => $permission->description,
                                                                                                                        ]);
        }
    }
    
    public function logPermissionGivenToRole(Permission $permission, Role $role, $value, $res = true) {
        
        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' gave Permission "'.$permission->code.'" to Role "'.$role->name.'" ', [
                                                                                                                'role_id'               => $role->id,
                                                                                                                'role_name'             => $role->name,
                                                                                                                'role_description'        => $role->description,
                                                                                                                'permission_id'         => $permission->id,
                                                                                                                'permission_code'       => $permission->code,
                                                                                                                'permission_description' => $permission->description,
                                                                                                                'permission_value'      => $value,
                                                                                                                ]);
        }
        else {
            self::logError($auth_name.' failed giving Permission "'.$permission->code.'" to Role "'.$role->name.'" ', [
                                                                                                                        'role_id'               => $role->id,
                                                                                                                        'role_name'             => $role->name,
                                                                                                                        'role_description'      => $role->description,
                                                                                                                        'permission_id'         => $permission->id,
                                                                                                                        'permission_code'       => $permission->code,
                                                                                                                        'permission_description' => $permission->description,
                                                                                                                        'permission_value'      => $value,
                                                                                                                        
                                                                                                                        ]);
        }
    }
    
    public function logPermissionRemovedFromRole(Permission $permission, Role $role, $res = true) {
        
        $auth_user = Auth::user();
        $auth_name = ($auth_user !== null) ? $auth_user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' removed Permission "'.$permission->code.'" from Role "'.$role->name.'" ', [
                                                                                                                'role_id'               => $role->id,
                                                                                                                'role_name'             => $role->name,
                                                                                                                'role_description'        => $role->description,
                                                                                                                'permission_id'         => $permission->id,
                                                                                                                'permission_code'       => $permission->code,
                                                                                                                'permission_description' => $permission->description,
                                                                                                                'permission_value'      => $permission->value,
                                                                                                                ]);
        }
        else {
            self::logError($auth_name.' failed removing Permission "'.$permission->code.'" from Role "'.$role->name.'" ', [
                                                                                                                        'role_id'               => $role->id,
                                                                                                                        'role_name'             => $role->name,
                                                                                                                        'role_description'      => $role->description,
                                                                                                                        'permission_id'         => $permission->id,
                                                                                                                        'permission_code'       => $permission->code,
                                                                                                                        'permission_description' => $permission->description,
                                                                                                                        'permission_value'      => $permission->value,
                                                                                                                        
                                                                                                                        ]);
        }
    }
    
    
    public function logPermissionCreated(Permission $permission, $res = true, $context = []) {
        
        if ($permission === null) {
            return;
        }

        $user = Auth::user();
        $auth_name = ($user !== null) ? $user->fullName() : '<no user>';
        
        if ($res) {
            self::logError($auth_name.' created Permission "'.$permission->code.'" - ', array_merge([ 
                                                                                'permission_id' => $permission->id,
                                                                                'code'          => $permission->code,
                                                                                'description'   => $permission->description,
                                                                                'uuid'          => $permission->uuid,
                                                                                ],
                                                                                $context));
        }
        else {
            self::log($auth_name.' failed to create permission - ', $context);
            
        }
    }
    
    
    public function logPermissionUpdated(Permission $new, Permission $old, $res = true) {
        
        if ($new === null) {
            return;
        }

        $user = Auth::user();
        $auth_name = ($user !== null) ? $user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' updated Permission "'.$new->code.
                            '" - Before : {id:'.$old->id.', code="'.$old->code.'", description="'.$old->description.
                             '"} - After : {id:'.$new->id.', code="'.$new->code.'", description="'.$new->description.
                             '"}', [
                                    'uuid'      => $old->uuid,
                                    ]   
                                    );
        }
        else {
            self::logError($auth_name.' failed to update Permission "'.$old->code.'" - ', [
                                                                                        'permission_id' => $old->id,
                                                                                        'code'          => $old->code,
                                                                                        'description'   => $old->description,
                                                                                        'uuid'      => $old->uuid,
                                                                                        ]);
        }
    }
    
    public function logPermissionDeleted(Permission $permission, $res = true) {

        $user = Auth::user();
        $auth_name = ($user !== null) ? $user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' deleted permission "'.$permission->code.'" - ',
                                    [
                                        'permission_id'    => $permission->id,
                                        'code'  => $permission->code,
                                        'description'   => $permission->description,
                                        'uuid'      => $permission->uuid,
                                        ]);
        }
        else {
            self::logError($auth_name.' failed to delete Permission "'.$permission->code.'" - ', [
                                                                                        'permission_id' => $permission->id,
                                                                                        'code'          => $permission->code,
                                                                                        'description'   => $permission->description,
                                                                                        'uuid'          => $permission->uuid,
                                                                                    ]);
        }
    }
    
    
    /// ROLES
    
    public function logRoleCreated(Role $role, $res = true, $context = []) {
        
        if ($role === null) {
            return;
        }

        $user = Auth::user();
        $auth_name = ($user !== null) ? $user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' created Role "'.$role->name.'" - ', array_merge([ 
                                                                                'role_id' => $role->id,
                                                                                'name'          => $role->name,
                                                                                'description'   => $role->description,
                                                                                'uuid'          => $role->uuid,
                                                                                ],
                                                                                $context));
        }
        else {
            self::logError($auth_name.' failed to create Role - ', $context);
            
        }
    }
    
    
    public function logRoleUpdated(Role $new, Role $old, $res = true) {
        
        if ($new === null) {
            return;
        }

        $user = Auth::user();
        $auth_name = ($user !== null) ? $user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' updated Role "'.$new->name.
                            '" - Before : {id:'.$old->id.', name="'.$old->name.'", description="'.$old->description.
                             '"} - After : {id:'.$new->id.', code="'.$new->name.'", description="'.$new->description.
                             '"}', [
                                    'uuid'      => $old->uuid,
                                    ]   
                                    );
        }
        else {
            self::logError($auth_name.' failed to update Role "'.$old->name.'" - ', [
                                                                                        'role_id' => $old->id,
                                                                                        'name'          => $old->name,
                                                                                        'description'   => $old->description,
                                                                                        'uuid'      => $old->uuid,
                                                                                        ]);
        }
    }
    
    public function logRoleDeleted(Role $role, $res = true) {

        $user = Auth::user();
        $auth_name = ($user !== null) ? $user->fullName() : '<no user>';
        
        if ($res) {
            self::log($auth_name.' deleted Role "'.$role->name.'" - ', [
                                                                                        'role_id' => $role->id,
                                                                                        'name'          => $role->name,
                                                                                        'description'   => $role->description,
                                                                                        'uuid'          => $role->uuid,
                                                                                    ]);
        }
        else {
            self::logError($auth_name.' failed to delete Role "'.$role->name.'" - ', [
                                                                                        'role_id' => $role->id,
                                                                                        'name'          => $role->name,
                                                                                        'description'   => $role->description,
                                                                                        'uuid'          => $role->uuid,
                                                                                    ]);
        }
    }
    
    
}




