<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Enums\UserStatus;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Laravel\Fortify\Contracts\PasskeyUser;
use Laravel\Fortify\PasskeyAuthenticatable;
use Laravel\Fortify\TwoFactorAuthenticatable;

/**
 * @property int $id
 * @property string $name
 * @property string|null $first_name
 * @property string|null $last_name
 * @property string|null $company
 * @property string|null $phone
 * @property string $email
 * @property string|null $username
 * @property string $password
 * @property int $credit
 * @property UserStatus $status
 * @property string|null $two_factor_secret
 * @property string|null $two_factor_recovery_codes
 * @property Carbon|null $two_factor_confirmed_at
 * @property string|null $remember_token
 * @property Carbon|null $email_verified_at
 * @property Carbon|null $created_at
 * @property Carbon|null $updated_at
 * @property-read Collection<int, Group> $groups
 *
 * @method static Builder|self member()
 * @method static Builder|self admin()
 */
#[Fillable(['name', 'first_name', 'last_name', 'company', 'phone', 'email', 'username', 'google_id', 'password', 'credit', 'status', 'email_verified_at'])]
#[Hidden(['password', 'two_factor_secret', 'two_factor_recovery_codes', 'remember_token'])]
class User extends Authenticatable implements PasskeyUser
{
    /** @use HasFactory<UserFactory> */
    use HasFactory, Notifiable, PasskeyAuthenticatable, TwoFactorAuthenticatable;

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
            'two_factor_confirmed_at' => 'datetime',
            'credit' => 'integer',
            'status' => UserStatus::class,
        ];
    }

    /**
     * Relasi ke grup pengguna (admin / members / developer).
     */
    public function groups(): BelongsToMany
    {
        return $this->belongsToMany(Group::class, 'users_groups');
    }

    public function ads(): HasMany
    {
        return $this->hasMany(Ad::class, 'user_id');
    }

    public function billings(): HasMany
    {
        return $this->hasMany(Billing::class, 'user_id');
    }

    public function creditHistory(): HasMany
    {
        return $this->hasMany(CreditHistory::class, 'user_id');
    }

    /**
     * Nama semua grup user (lowercase) — cache hasil per request.
     *
     * @return Collection<int, string>
     */
    public function groupNames(): Collection
    {
        return $this->groups->pluck('name');
    }

    /**
     * Apakah user tergabung pada salah satu grup yang diberikan?
     *
     * @param  string|array<int, string>  $groups
     */
    public function inGroup(string|array $groups): bool
    {
        $groups = array_map('strtolower', (array) $groups);

        return $this->groupNames()
            ->map(fn (string $name) => strtolower($name))
            ->intersect($groups)
            ->isNotEmpty();
    }

    public function isAdmin(): bool
    {
        return $this->inGroup([Group::ADMIN, Group::DEVELOPER]);
    }

    public function isMember(): bool
    {
        return $this->inGroup(Group::MEMBERS);
    }

    public function isDeveloper(): bool
    {
        return $this->inGroup(Group::DEVELOPER);
    }

    /**
     * Apakah user boleh mengelola seluruh data lintas pengguna? (admin/developer)
     */
    public function canManageAll(): bool
    {
        return $this->isAdmin();
    }

    /**
     * Scope: hanya user grup members.
     */
    public function scopeMember(Builder $query): Builder
    {
        return $query->whereHas('groups', fn (Builder $q) => $q->where('name', Group::MEMBERS));
    }

    /**
     * Scope: user grup admin/developer.
     */
    public function scopeAdmin(Builder $query): Builder
    {
        return $query->whereHas('groups', fn (Builder $q) => $q->whereIn('name', [Group::ADMIN, Group::DEVELOPER]));
    }
}
