<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Notifications\ResetPasswordNotification;
use App\Notifications\VerifyEmailNotification;
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasName;
use Filament\Models\Contracts\HasTenants as FilamentHasTenants;
use Filament\Panel;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Laravel\Sanctum\HasApiTokens;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'email',
        'name',
        'password',
        'username',
        'preferred_locale',
        'first_name',
        'last_name',
        'address',
        'phone',
        'role',
        'tenant_id',
        'pending_purchase',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

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

    public function isSuperAdmin(): bool
    {
        return self::isSuperAdminRole($this->role);
    }

    public static function isSuperAdminRole(?string $role): bool
    {
        return in_array($role, ['super_admin', 'superadmin'], true);
    }

    /**
     * Retrieve the user by the given credentials.
     */
    public function retrieveByCredentials(array $credentials)
    {
        if ($this->getProvider()->hasTable($this->getTable())) {
            return $this->newModelQuery()
                ->where(function ($query) use ($credentials) {
                    // Handle 'login' field for email or username
                    if (isset($credentials['login'])) {
                        $login = $credentials['login'];
                        $query->where('email', $login)
                            ->orWhere('username', $login);
                    } else {
                        foreach ($this->getAuthIdentifiers() as $key => $value) {
                            $query->where($key, $value);
                        }
                    }
                })
                ->first();
        }

        return null;
    }

    public function sendEmailVerificationNotification(): void
    {
        $this->notify(new VerifyEmailNotification);
    }

    public function sendPasswordResetNotification($token): void
    {
        $this->notify(new ResetPasswordNotification($token));
    }

    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => trim(($this->first_name ?? '').' '.($this->last_name ?? '')) ?: $this->name,
        );
    }

    public function getFilamentName(): string
    {
        if ($this->first_name && $this->last_name) {
            return trim($this->first_name.' '.$this->last_name);
        }

        return $this->username ?? $this->email ?? 'Unnamed User';
    }

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class);
    }

    public function canAccessPanel(Panel $panel): bool
    {
        if (! $this->email_verified_at && ! $this->isSuperAdmin()) {
            return false;
        }

        return match ($panel->getId()) {
            'superadmin' => $this->isSuperAdmin(),
            'admin' => $this->role === 'tenant_admin',
            default => false,
        };
    }

    public function canAccessTenant(Model $tenant): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        $ownedTenant = $this->tenant;

        if (! $ownedTenant) {
            return false;
        }

        return (int) $tenant->getKey() === (int) $ownedTenant->getKey();
    }

    public function getTenants(Panel $panel): array|Collection
    {
        if ($this->isSuperAdmin()) {
            return Tenant::query()->orderBy('name')->get();
        }

        $tenant = $this->tenant;

        return $tenant ? collect([$tenant]) : collect();
    }

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

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