<?php

namespace App\Models;

use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Models\GroupPermission;
use App\Models\ProductRights;
use App\Models\Group;
use App\Models\Organisation;
use App\Mail\UserInvitation;
use Illuminate\Support\Facades\Mail;

use App\Jobs\SendAuthEmail;

use Illuminate\Support\Str;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'phone',
        'password',
        'question_one',
        'question_two',
        'question_three',
        'answer_one',
        'answer_two',
        'answer_three',
        'billing',
        'signup_token',
        'reset_token',
        'group_id',
        'organisation_id',
        'suspended_at',
        'reset_at',
        'signup_at',
        'login_at'
    ];

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

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'reset_at' => 'datetime',
        'signup_at' => 'datetime',
        'login_at' => 'datetime',
    ];

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }

    public static function generateEmailToken($_field) {
        $length = 32;
        $email_token = Str::random($length);
        
        while(self::where($_field, '=', $email_token)->count()) {
            $email_token = Str::random($length++);
        }

        return $email_token;
    }

    public function sendSetupEmail() {
        // Update user itself
        $this->signup_token = self::generateEmailToken('signup_token');
        $this->save();

        // Queue up email
        SendAuthEmail::dispatch('setup', $this->email, $this->signup_token);
    }

    public function sendResetEmail() {
        // Update user itself
        $this->reset_token = self::generateEmailToken('reset_token');
        $this->save();

        // Queue up email
        SendAuthEmail::dispatch('reset', $this->email, $this->reset_token);
    }

    // Gets the permissions for a given user minus any they fail a conditional check for.
    public function getPermissions() {
        if($this->group_id === null) {
            return [];
        }

        $filtered_permissions = [];
        $unfiltered_permissions = GroupPermission::where('group_id', '=', $this->group_id)->get()->toArray();

        $product_access = ProductRights::where('organisation_id', '=', $this->organisation_id)->orWhere('user_id', '=', $this->id)->get()->pluck('name')->toArray();

        foreach($unfiltered_permissions as $x) {
            if($x['status'] == 1 && ($x['conditional'] == null || array_search($x['conditional'], $product_access))) {
                $filtered_permissions[] = $x['permission'];
            }
        }

        return $filtered_permissions;
    }

    public function canDo($_x) {
        if($this->group_id === null) {
            return false;
        }

        $permissions = GroupPermission::where('group_id', '=', $this->group_id)->get()->keyBy('permission');
        $product_access = ProductRights::where('organisation_id', '=', $this->organisation_id)->orWhere('user_id', '=', $this->id)->get()->pluck('name');

        
        if(!is_array($_x )) {
            $_x = (array)$_x;
        }

        foreach($_x as $key) {
            // If the user is straight up lacking the scope, or if the scope is set to zero, or if the user does not have product access when there's a conditional.
            if(!isset($permissions[$key]) || $permissions[$key]['status'] == 0 || ($permissions[$key]['conditional'] != null && !array_search($permissions[$key]['conditional'], $product_access))) {
                return false;
            }
        }

        return true;
    }
}
