<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

use App\Models\User;
use App\Models\Role;
use App\Models\UsersRole;
use App\Models\Permission;
use App\Models\PermissionsRole;
use App\Models\DelegateUsersPermission;
use App\Models\UsersInteraction;
use App\Models\UsersInteractionsFile;
use App\Models\KeysTracking;
use App\Models\KeysTrackingsReplacementFile;
use App\Models\LoanableItemsTracking;
use App\Models\LoanableItemsTrackingsPicture;
use App\Models\LoanableItemsTrackingsReplacementFile;
use App\Models\UsersVehicle;
use App\Models\UsersVehiclesPicture;
use App\Models\UsersVehiclesFile;
use App\Models\UsersChildren;
use App\Models\UsersChildrensPicture;
use App\Models\UsersChildrensFile;
use App\Models\UsersPet;
use App\Models\UsersPetsShot;
use App\Models\UsersPetsPicture;
use App\Models\UsersPetsFile;
use App\Models\UsersOthersLiving;
use App\Models\UsersOthersLivingsPicture;
use App\Models\UsersOthersLivingsFile;
use App\Models\UsersEmergenciesContact;
use App\Models\UsersEmergenciesContactsPicture;


class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'system_id',
        'user_prefix_id',
        'firstname',
        'middlename',
        'lastname',
        'user_suffix_id',
        'uuid',
        'email',
        'password',
        'owner_id',
        'creator_id',
        'goolge_id',
        'facebook_id',
        'linkedin_id',
        'website_id',
        'about_me',
        'is_active',
        'avatar'
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
    
    public function assignedRoles()
    {
        return $this->hasMany(UsersRole::class);
    }

    public function addresses()
    {
        return $this->hasMany(UsersAddress::class);
    }

    public function phoneNumbers()
    {
        return $this->hasMany(UsersNumber::class);
    }
    
    public function profile()
    {
        return $this->hasOne(UsersProfile::class);
    }
    
    public function pictures()
    {
        return $this->hasMany(UsersPicture::class);
    }
    
    public function emergenciesContacts($user_id)
    {
        $emergency_contacts = UsersEmergenciesContact::where(['user_id'=>$user_id])->get();
        
        $emergency_contacts = (!empty($emergency_contacts)) ? json_decode(json_encode($emergency_contacts), true) : [];
        
        for($i=0; $i<count($emergency_contacts); $i++){
            
            $user_emergency_contact_id = $emergency_contacts[$i]['id'];
            
            $pictures = UsersEmergenciesContactsPicture::where(['user_emergency_contact_id'=>$user_emergency_contact_id])->get();
            $emergency_contacts[$i]['pictures'] = (!empty($pictures)) ? $pictures->toArray() : [];
            
        }
        
        return $emergency_contacts;
        
    }
    
    public function notifications()
    {
        return $this->hasMany(UsersNotification::class);
    }
    
    public function files()
    {
        return $this->hasMany(UsersFile::class);
    }
    
    public function staffFiles()
    {
        return $this->hasMany(UsersStaffFile::class);
    }
    
    public function managersFiles()
    {
        return $this->hasMany(UsersManagersFile::class);
    }
    
    public function ownersFiles()
    {
        return $this->hasMany(UsersOwnersFile::class);
    }
    
    public function listingsInfos()
    {
        return $this->hasMany(UsersListingsInfo::class);
    }
    
    public function interactions($user_id)
    {
        
        $interactions = UsersInteraction::where(['user_id'=>$user_id])->get();
            
        $interactions = (!empty($interactions)) ? $interactions->toArray() : [];
        
        for($i=0; $i<count($interactions); $i++){
            
            $user_interaction_id = $interactions[$i]['id'];
            
            $files = UsersInteractionsFile::where(['user_interaction_id'=>$user_interaction_id])->get();
            $interactions[$i]['files'] = (!empty($files)) ? $files->toArray() : [];
            
        }
        
        return $interactions;
        
    }
    
    public function keysTrackings($user_id)
    {
        
        $keys_trackings = KeysTracking::where(['assigned_to'=>$user_id])->get();
            
        $keys_trackings = (!empty($keys_trackings)) ? $keys_trackings->toArray() : [];
        
        for($i=0; $i<count($keys_trackings); $i++){
            
            $key_tracking_id = $keys_trackings[$i]['id'];
            
            $replacement_files = KeysTrackingsReplacementFile::where(['key_tracking_id'=>$key_tracking_id])->get();
            $keys_trackings[$i]['replacement_files'] = (!empty($replacement_files)) ? $replacement_files->toArray() : [];
            
        }
        
        return $keys_trackings;
        
    }
    
    public function LoanableItemsTrackings($user_id)
    {
        
        $loanable_item_trackings = LoanableItemsTracking::where(['assigned_to'=>$user_id])->get();
            
        $loanable_item_trackings = (!empty($loanable_item_trackings)) ? $loanable_item_trackings->toArray() : [];
        
        for($i=0; $i<count($loanable_item_trackings); $i++){
            
            $loanable_item_tracking_id = $loanable_item_trackings[$i]['id'];
            
            $replacement_files = LoanableItemsTrackingsReplacementFile::where(['loanable_item_tracking_id'=>$loanable_item_tracking_id])->get();
            $loanable_item_trackings[$i]['replacement_files'] = (!empty($replacement_files)) ? $replacement_files->toArray() : [];
            
            $replacement_pictures = LoanableItemsTrackingsPicture::where(['loanable_item_tracking_id'=>$loanable_item_tracking_id])->get();
            $replacement_pictures = (!empty($replacement_pictures)) ? $replacement_pictures->toArray() : [];
            
            $item_given_pictures = $item_return_pictures = [];
            
            foreach($replacement_pictures as $rp){
                if($rp['is_given'] == 1){
                    array_push($item_given_pictures, $rp);
                }
                else if($rp['is_return'] == 1){
                    array_push($item_return_pictures, $rp);
                }
            }
            
            // $loanable_item_trackings[$i]['replacement_pictures'] = (!empty($replacement_pictures)) ? $replacement_pictures->toArray() : [];
            $loanable_item_trackings[$i]['item_given_pictures'] = $item_given_pictures;
            $loanable_item_trackings[$i]['item_return_pictures'] = $item_return_pictures;
            
        }
        
        return $loanable_item_trackings;
        
    }
    
    public function vehicles($user_id)
    {
        
        $vehicles = UsersVehicle::where(['user_id'=>$user_id])->get();
            
        $vehicles = (!empty($vehicles)) ? $vehicles->toArray() : [];
        
        for($i=0; $i<count($vehicles); $i++){
            
            $vehicle_id = $vehicles[$i]['id'];
            
            $pictures = UsersVehiclesPicture::where(['user_vehicle_id'=>$vehicle_id])->get();
            $vehicles[$i]['pictures'] = (!empty($pictures)) ? $pictures->toArray() : [];
            
            $files = UsersVehiclesFile::where(['user_vehicle_id'=>$vehicle_id])->get();
            $vehicles[$i]['files'] = (!empty($files)) ? $files->toArray() : [];
            
        }
        
        return $vehicles;
        
    }
    
    public function children($user_id)
    {
        
        $children = UsersChildren::where(['user_id'=>$user_id])->get();
            
        $children = (!empty($children)) ? $children->toArray() : [];
        
        for($i=0; $i<count($children); $i++){
            
            $children_id = $children[$i]['id'];
            
            $pictures = UsersChildrensPicture::where(['user_children_id'=>$children_id])->get();
            $children[$i]['pictures'] = (!empty($pictures)) ? $pictures->toArray() : [];
            
            $files = UsersChildrensFile::where(['user_children_id'=>$children_id])->get();
            $children[$i]['files'] = (!empty($files)) ? $files->toArray() : [];
            
            $files = UsersChildrensFile::where(['user_children_id'=>$children_id])->get();
            $children[$i]['private_files'] = (!empty($files)) ? $files->toArray() : [];
            
        }
        
        return $children;
        
    }
    
    public function pets($user_id)
    {
        
        $pets = UsersPet::where(['user_id'=>$user_id])->get();
            
        $pets = (!empty($pets)) ? $pets->toArray() : [];
        
        for($i=0; $i<count($pets); $i++){
            
            $pet_id = $pets[$i]['id'];
            
            $shots = UsersPetsShot::where(['user_pet_id'=>$pet_id])->get();
            $pets[$i]['shots'] = (!empty($shots)) ? $shots->toArray() : [];
            
            $pictures = UsersPetsPicture::where(['user_pet_id'=>$pet_id])->get();
            $pets[$i]['pictures'] = (!empty($pictures)) ? $pictures->toArray() : [];
            
            $files = UsersPetsFile::where(['user_pet_id'=>$pet_id])->get();
            $pets[$i]['files'] = (!empty($files)) ? $files->toArray() : [];
            
            $files = UsersPetsFile::where(['user_pet_id'=>$pet_id])->get();
            $pets[$i]['private_files'] = (!empty($files)) ? $files->toArray() : [];
            
        }
        
        return $pets;
        
    }
    
    public function otherLivings($user_id)
    {
        
        $other_livings = UsersOthersLiving::where(['user_id'=>$user_id])->get();
            
        $other_livings = (!empty($other_livings)) ? $other_livings->toArray() : [];
        
        for($i=0; $i<count($other_livings); $i++){
            
            $other_living_id = $other_livings[$i]['id'];
            
            $pictures = UsersOthersLivingsPicture::where(['user_other_living_id'=>$other_living_id])->get();
            $other_livings[$i]['pictures'] = (!empty($pictures)) ? $pictures->toArray() : [];
            
            $files = UsersOthersLivingsFile::where(['user_other_living_id'=>$other_living_id])->get();
            $other_livings[$i]['files'] = (!empty($files)) ? $files->toArray() : [];
            
        }
        
        return $other_livings;
        
    }
    
    public function employments()
    {
        return $this->hasMany(UsersEmployment::class);
    }
    
    public function references()
    {
        return $this->hasMany(UsersReference::class);
    }
    
    public function previousHousings()
    {
        return $this->hasMany(UsersPreviousHousing::class);
    }
    

    public function subscriptions()
    {
        return $this->hasMany(UsersSubscription::class);
    }
    
    public function getOwnerOfUser($user_id){
        $owner_id = $user_id;   // will write it's logic later
        $user = User::find($user_id);
        $owner_id = (!empty($user)) ? $user->owner_id : $user_id;
        return $owner_id;
    }
    
    public function checkPermission($permission_slug = ''){
        
        $has_permission = 0;
        $permission_id = 0;
        $has_permission_found = 0;
        $has_delegate_permission_found = 0;
        
        $permission = Permission::where(['slug'=>$permission_slug])->first();
        
        if(empty($permission)){
            return false;
        }
        
        $permission_id = $permission->id;
        
        // get currently logged in user id
        $user_id = auth()->user()->id;
        
        $assigned_roles = UsersRole::select(['role_id'])->where(['user_id' => $user_id])->get()->toArray();
        
        $assigned_roles_ids = array_column($assigned_roles, 'role_id');
        
        // first check if super admin then return true without further check
        if(in_array("1", $assigned_roles_ids)){
            return true;
        }
        
        foreach($assigned_roles_ids as $r){
            $permission_role = PermissionsRole::where(['permission_id'=>$permission_id, 'role_id'=> $r])->first();
            if(!empty($permission_role)){
                $has_permission_found = 1;
                break;
            }
        }
        
        
        // now check for delegate access
        $delegate_users_permissions = DelegateUsersPermission::where(['permission_id' => $permission_id, 'user_id' => $user_id])->first();
        
        if(!empty($delegate_users_permissions)){
            
            if($has_permission_found){    
                // as permission found agaist logged in user's roles
                // now check if this permission taken(banned or blocked) for logged in user as delegate(special) access
                
                if($delegate_users_permissions->taken == 1){
                    return false;  // permission taken or blocked through special permission
                }
                
            }
            else{
                // as permission not found agaist logged in user's roles
                // now check if this permission granted to logged in user as delegate(special) access
                
                if($delegate_users_permissions->granted == 1){
                    return true;  // permission granted through special permission
                }
                
            }
            
        }
        
        return $has_permission_found;
        
    }
    
    public function getAllPermissionsByUser($user_id){
        
        // get all roles assigned to users
        $user = User::find($user_id);
        
        $user_roles = UsersRole::where(['user_id'=>$user_id])
                        ->join('roles', 'users_roles.role_id', '=', 'roles.id')
                        ->get(['users_roles.role_id', 'roles.role']);
                        
        if(!empty($user_roles)){
            $user_roles = $user_roles->toArray();
            for($i=0; $i<count($user_roles); $i++){
                $role_id =  $user_roles[$i]['role_id'];
                
                $permissions = PermissionsRole::where(['role_id'=>$role_id])
                                ->join('permissions', 'permissions_roles.permission_id', '=', 'permissions.id')
                                ->get(['permissions_roles.permission_id', 'permissions.permission']);
                                    
                
                $user_roles[$i]['permissions'] = (!empty($permissions)) ? $permissions->toArray() : [];
            }
            
        }
        else{
            $user_roles = [];
        }
        
        // get granted delegate access
        $granted_delegate_access = DelegateUsersPermission::where(['user_id'=>$user_id, 'granted'=>1, 'taken'=>0])
                                        ->join('permissions', 'delegate_users_permissions.permission_id', '=', 'permissions.id')
                                        ->get(['delegate_users_permissions.permission_id', 'permissions.permission']);
        
        // get taken delegate access
        $taken_delegate_access = DelegateUsersPermission::where(['user_id'=>$user_id, 'granted'=>0, 'taken'=>1])
                                        ->join('permissions', 'delegate_users_permissions.permission_id', '=', 'permissions.id')
                                        ->get(['delegate_users_permissions.permission_id', 'permissions.permission']);
        
        
        
        $data = [
            'user_roles' => $user_roles,
            'granted_delegate_access' => $granted_delegate_access,
            'taken_delegate_access' => $taken_delegate_access,
        ];
        
        return $data;
        
    }
    
    public function getAllPermissionsByRole($role_id){
        
        $user = Role::find($role_id);
        
        $permissions = PermissionsRole::where(['role_id'=>$role_id])
                        ->join('permissions', 'permissions_roles.permission_id', '=', 'permissions.id')
                        ->get(['permissions_roles.permission_id', 'permissions.permission']);

        return ['permissions' => $permissions];
        
    }
    
}
