<?php

namespace App\Models;

use App\Traits\UniqueId;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasFactory, Notifiable, HasRoles, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'user_type',
        'email',
        'phone',
        'password',
        'picture',
        'location',
        'latitude',
        'longitude',
        'club_name',
        'verification_code',
        'verification_code_sent_at',
        'rank',
        'status',
        'social_id',
        'social_type',
        'customer_stripe_id',
    ];

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

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];

    protected $appends = [
        'is_favorite'
    ];

    /**
     * Booted method of the model
     */
    protected static function booted(): void
    {
        static::creating(function (User $model) {
            // In case of user verification by code
            // $model->verification_code = mt_rand(100000, 999999);
            // $model->verification_code_sent_at = now();

            $model->email_verified_at = now();
        });
    }

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }

    /**
     * Get the user's picture
     *
     * @return Attribute
     */
    protected function picture(): Attribute
    {
        return new Attribute(
            get: fn ($value) => $value !== null ? env('UPLOAD_URL') . $value : env('UPLOAD_URL') . 'users/default-avatar.jpg',
        );
    }

    public function getIsFavoriteAttribute()
    {
        $fav = Favorite::where([
            'user_id' => auth()->user()->id,
            'favoritable_type' => 'App\Models\User',
            'favoritable_id' => $this->id
        ])
            ->first();
        if ($fav) {
            return true;
        }
        return false;
    }


    /**
     * Determine if the user has verified their email address.
     *
     * @return bool
     */
    public function hasVerifiedEmail(): bool
    {
        return !is_null($this->email_verified_at);
    }

    /**
     * Check for validated code
     *
     * @return bool
     */
    public function hasValidCode(): bool
    {
        $diff = now()->diffInMinutes($this->verification_code_sent_at);

        return !is_null($this->verification_code) && $diff <= 60;
    }

    /**
     * Mark the given user's email as verified.
     *
     * @return bool
     */
    public function markUserVerified(): bool
    {
        return $this->forceFill([
            'email_verified_at' => $this->freshTimestamp(),

            // In case of user verification by code
            'verification_code' => null,
            'verification_code_sent_at' => null,
        ])->save();
    }

    /**
     * Retrieve associated user devices
     *
     * @return HasMany
     */
    public function devices(): HasMany
    {
        return $this->hasMany(UserDevice::class);
    }

    /**
     * Retrieve associated favorites
     *
     * @return MorphMany
     */
    public function favorites(): MorphMany
    {
        return $this->morphMany(Favorite::class, 'favoritable');
    }

    /**
     * Retrieve associated events
     *
     * @return BelongsToMany
     */
    public function events(): BelongsToMany
    {
        return $this->belongsToMany(Event::class)->using(EventUser::class);
    }

    /**
     * Retrieve associated tournaments
     *
     * @return HasMany
     */
    public function tournaments(): HasMany
    {
        return $this->hasMany(TournamentUser::class);
    }

    /**
     * Retrieve associated reviews
     *
     * @return MorphMany
     */
    public function reviews(): MorphMany
    {
        return $this->morphMany(Review::class, 'rateable');
    }

    /**
     * Retrieve associated cards
     *
     * @return HasMany
     */
    public function cards(): HasMany
    {
        return $this->hasMany(Card::class);
    }

    /**
     * Retrieve associated posts
     *
     * @return HasMany
     */
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    /**
     * Retrieve associated clubs
     *
     * @return HasMany
     */
    public function clubs(): HasMany
    {
        return $this->hasMany(Club::class);
    }

    public function invitations(): HasMany
    {
        return $this->hasMany(Invitation::class, 'player_id');
    }

    public function activities()
    {
        return $this->hasMany(Activity::class);
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }

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

    public function subscription()
    {
        return $this->hasOne(Subscription::class);
    }
}
