<?php

namespace DefStudio\GameEngine\Models;

use Laravel\Sanctum\HasApiTokens;
use DefStudio\GameEngine\Enums\Role;
use Laravel\Jetstream\HasProfilePhoto;
use Spatie\Permission\Traits\HasRoles;
use DefStudio\GameEngine\Enums\Feature;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Collection;
use Laravel\Fortify\TwoFactorAuthenticatable;
use DefStudio\Impersonator\Concerns\Impersonate;
use DefStudio\GameEngine\Models\Concerns\HasTeams;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use DefStudio\GameEngine\Database\Factories\UserFactory;
use Illuminate\Contracts\Translation\HasLocalePreference;
use DefStudio\GameEngine\Models\Concerns\HasOrganizations;
use DefStudio\GameEngine\Models\Concerns\CanCheckRelationships;

/**
 * @property int $id
 * @property string $name
 * @property string $email
 * @property string $password
 * @property string $locale
 * @property int|null $current_organization_id
 * @property-read Collection<int, Team> $teams
 * @property-read Collection<int, Team> $current_teams
 * @property-read Collection<int, Organization> $organizations
 * @property-read Organization|null $current_organization
 *
 * @method static UserFactory factory(array|callable|int|null $count = null, array|callable $state = [])
 */
abstract class User extends Authenticatable implements HasLocalePreference
{
    use HasApiTokens;
    use HasFactory;
    use Notifiable;
    use HasProfilePhoto;
    use TwoFactorAuthenticatable;
    use CanCheckRelationships;
    use HasOrganizations;
    use HasTeams;
    use HasRoles{
        HasRoles::hasRole as _hasRole;
        HasRoles::hasPermissionTo as _hasPermissionTo;
    }
    use Impersonate;

    protected $fillable = [
        'name',
        'email',
        'password',
        'locale',
    ];

    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_recovery_codes',
        'two_factor_secret',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    protected $attributes = [
        'locale' => 'en',
    ];

    protected $with = ['organizations'];

    /**
     * @noinspection PhpMissingReturnTypeInspection
     */
    protected static function newFactory()
    {
        return UserFactory::new();
    }

    public function preferredLocale(): string
    {
        return $this->locale;
    }

    public function can_be_impersonated(): bool
    {
        if (!Feature::impersonate->enabled()) {
            return false;
        }

        return !$this->hasRole(Role::super_admin->value);
    }

    public function can_impersonate(): bool
    {
        if (!Feature::impersonate->enabled()) {
            return false;
        }

        return $this->hasRole(Role::super_admin);
    }

    public function hasRole($roles, string $guard = null): bool
    {
        if ($roles instanceof Role) {
            $roles = $roles->value;
        }

        return $this->_hasRole($roles, $guard);
    }

    public function hasPermissionTo($permission, $guardName = null): bool
    {
        if ($permission instanceof Role) {
            $permission = $permission->value;
        }

        return $this->_hasPermissionTo($permission, $guardName);
    }
}
