<?php

namespace App\Models;

use App\Enums\RoleName;
use App\Enums\UserStatus;
use Database\Factories\UserFactory;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
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\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

#[Fillable(['name', 'email', 'password', 'locale', 'status'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable implements FilamentUser, MustVerifyEmail
{
    private const ADMIN_PORTAL_ROLES = [RoleName::SuperAdmin, RoleName::Admin];

    /** @use HasFactory<UserFactory> */
    use HasApiTokens, HasFactory, Notifiable, SoftDeletes;

    /**
     * Kullanıcı alanlarına uygulanacak güvenli tür dönüşümlerini tanımlar.
     *
     * @return array<string, string>
     *
     * @author Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'last_login_at' => 'datetime',
            'password' => 'hashed',
            'status' => UserStatus::class,
        ];
    }

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class)->withTimestamps()
            ->orderByRaw("CASE roles.name WHEN 'super_admin' THEN 1 WHEN 'admin' THEN 2 WHEN 'support' THEN 3 WHEN 'customer' THEN 4 ELSE 5 END");
    }

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

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

    /**
     * Müşteriye sunucu tarafında bağlanmış görev sonuçlarını döndürür.
     *
     * @author Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
     */
    public function earnTaskResults(): HasMany
    {
        return $this->hasMany(EarnTaskResult::class);
    }

    public function hasRole(RoleName|string $role): bool
    {
        $name = $role instanceof RoleName ? $role->value : $role;

        return $this->roles()->where('name', $name)->exists();
    }

    public function hasPermission(string $permission): bool
    {
        if ($this->hasRole(RoleName::SuperAdmin)) {
            return true;
        }

        return $this->roles()->whereHas('permissions', fn ($query) => $query->where('name', $permission))->exists();
    }

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

    public function hasManagementRole(): bool
    {
        return $this->roles()->whereIn('name', array_map(
            static fn (RoleName $role): string => $role->value,
            self::ADMIN_PORTAL_ROLES,
        ))->exists();
    }

    /**
     * Kullanıcının diğer rollerinden bağımsız olarak müşteri paneline erişimini denetler.
     *
     * @return bool Aktif kullanıcı customer rolüne sahipse true.
     *
     * @author Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
     */
    public function canAccessCustomerPortal(): bool
    {
        return ! $this->trashed() && $this->isActive()
            && $this->hasRole(RoleName::Customer);
    }

    public function canAccessAdminPortal(): bool
    {
        return ! $this->trashed() && $this->isActive() && $this->hasVerifiedEmail()
            && $this->hasManagementRole() && $this->hasPermission('admin.access');
    }

    public function canAccessPanel(Panel $panel): bool
    {
        return $panel->getId() === 'admin' && $this->canAccessAdminPortal();
    }
}
