<?php

namespace App\Models;

use App\Enums\UserStatus;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;

class User extends Authenticatable implements MustVerifyEmail
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable;

    /**
     * `status` and `email_verified_at` are deliberately excluded: both are
     * privilege-adjacent and must be set explicitly, never by mass assignment.
     */
    protected $fillable = [
        'name',
        'email',
        'phone',
        'password',
    ];

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

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'last_login_at' => 'datetime',
            'password' => 'hashed',
            'status' => UserStatus::class,
        ];
    }

    /** Cached permission slugs for the current request. */
    protected ?Collection $permissionCache = null;

    // ---------------------------------------------------------------- Relations

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class);
    }

    public function applicant(): HasOne
    {
        return $this->hasOne(Applicant::class);
    }

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

    // ------------------------------------------------------------ Authorization

    public function hasRole(string ...$slugs): bool
    {
        return $this->roles->whereIn('slug', $slugs)->isNotEmpty();
    }

    public function isSuperAdmin(): bool
    {
        return $this->hasRole(Role::SUPER_ADMIN);
    }

    /**
     * All permission slugs granted through this user's roles.
     */
    public function permissions(): Collection
    {
        return $this->permissionCache ??= $this->roles
            ->loadMissing('permissions')
            ->flatMap(fn (Role $role) => $role->permissions->pluck('slug'))
            ->unique()
            ->values();
    }

    public function hasPermission(string $slug): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        return $this->permissions()->contains($slug);
    }

    public function hasAnyPermission(string ...$slugs): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        return $this->permissions()->intersect($slugs)->isNotEmpty();
    }

    /** Any permission at all implies access to the staff back office. */
    public function isStaff(): bool
    {
        return $this->isSuperAdmin() || $this->roles->isNotEmpty();
    }

    public function forgetPermissionCache(): void
    {
        $this->permissionCache = null;
    }

    // ----------------------------------------------------------------- Helpers

    public function isActive(): bool
    {
        return $this->status === UserStatus::Active;
    }

    public function initials(): string
    {
        return collect(explode(' ', trim($this->name)))
            ->filter()
            ->take(2)
            ->map(fn (string $part) => mb_strtoupper(mb_substr($part, 0, 1)))
            ->implode('');
    }

    public function firstName(): string
    {
        return explode(' ', trim($this->name))[0] ?? $this->name;
    }
}
