<?php

namespace App\Models;

use App\Events\UserRegistered;
use App\Mail\PasswordResetRequested;
use App\Models\Advisories\AdvisoryMember;
use App\Models\Applications\Conclusion;
use App\Models\Companies\Company;
use App\Models\Companies\CompanyMember;
use App\Models\Companies\CompanyMemberRole;
use App\Models\Objects\Field;
use App\Support\HasRolesUuid;
use App\Support\HasSocialLogin;
use App\Support\RelationValuesTrait;
use App\Support\UuidScopeTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable {
    use Notifiable, UuidScopeTrait, HasFactory, HasApiTokens, HasRoles, SoftDeletes, HasSocialLogin, RelationValuesTrait, HasRolesUuid {
        HasRolesUuid::getStoredRole insteadof HasRoles;
    }

    protected $dates = [
        'deleted_at'
    ];

    protected $fillable = [
        'uuid',
        'asset_id',
        'name',
        'phone',
        'email',
        'position',
        'password'
    ];

    protected $hidden = [
        'id',
        'password',
        'remember_token',
    ];



    public function socialProviders(): HasMany {
        return $this->hasMany(SocialProvider::class);
    }

	public function avatar(): BelongsTo {
    	return $this->belongsTo(Asset::class, 'asset_id');
	}

    public function companies(): BelongsToMany {
        return $this->belongsToMany(Company::class, 'company_members');
    }

    public function membership(): HasMany {
        return $this->hasMany(CompanyMember::class);
    }
    public function advisoryMembership(): HasManyThrough {
        return $this->hasManyThrough(AdvisoryMember::class, CompanyMember::class);
    }


    public function applicationConclusions(): HasMany {
        return $this->hasMany(Conclusion::class, 'author_id');
    }


    public function getInitialsAttribute(): string {
        return collect(explode(' ', $this->name))->slice(0, 2)->map(function($item) {
            return Str::upper(Str::substr($item, 0, 1));
        })->join('');
    }

    public function getFirstAndMidNameAttribute(): string {
        return collect(explode(' ', $this->name))->slice(1, 2)->join(' ');
    }

    public function getRoleAttribute() {
        return $this->roles()->first();
    }
    public function getIsAdminAttribute(): bool {
        return $this->hasRole('Administrator');
    }
    public function getIsEditorAttribute(): bool {
        return $this->hasRole('Editor');
    }


    public function getPrivilegesAttribute(): array {
        return [
            'admin' => $this->isAdmin,
            'editor' => $this->isEditor
        ];
    }




    public static function getByData($data, $triggerEvent = false) {
        $result = false;
        if ($email = trim($data['email'] ?? null)) {
            $result = self::query()->where(['email' => $email])->withTrashed()->first();
            if (!$result) {
                $password = $data['password'] ?? self::makeDefaultPassword();
                $result = self::create(['email' => $email, 'password' => $password]);
                $result->update(['name' => trim($data['name'] ?? null), 'phone' => trim($data['phone'] ?? null), 'position' => $data['position'] ?? null]);
                $result->syncRoles($data['role'] ?? 'User');
                if ($triggerEvent) event(new UserRegistered($result, $password));
            } else {
                if ($val = trim($data['phone'] ?? null)) $result->update(['phone' => $val]);
                if ($val = trim($data['position'] ?? null)) $result->update(['position' => $val]);
                if ($result->trashed()) $result->restore();
            }
            if ($val = $data['avatar'] ?? null) $result->setAvatar($val);
        }
        return $result;
    }

    public function setAvatar($val) {
        $asset = Asset::byUuid($val)->first();
        $this->update(['asset_id' => $asset->id ?? null]);
    }



    public static function create(array $attributes = []) {
        if (array_key_exists('password', $attributes)) {
            $attributes['password'] = Hash::make($attributes['password']);
        }
        return static::query()->create($attributes);
    }


    public function setPassword(string $password): bool {
        return $this->update(['password' => Hash::make($password)]);
    }

    public function checkPassword(string $password): bool {
        return Hash::check($password, $this->password);
    }

    public static function makeDefaultPassword(): string {
        return App::environment('production') ? Str::random(8) : 'Qwerty1!';
    }


    public function sendPasswordResetNotification($token) {
        Mail::to($this->email)->send(new PasswordResetRequested($this, $token));
    }

}
