<?php

namespace App\Models;

use App\Models\Poke;
use Laravel\Sanctum\HasApiTokens;
use Spatie\MediaLibrary\HasMedia;
use Illuminate\Support\Facades\Auth;
use App\Models\BloodBank\BloodRequest;
use Spatie\Permission\Traits\HasRoles;
use App\Models\BloodBank\BloodDonation;
use Illuminate\Notifications\Notifiable;

use App\Models\BloodBank\DriveRegistration;
use Spatie\MediaLibrary\InteractsWithMedia;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'username',
        'name',
        'device_token',
        'first_name',
        'last_name',
        'email',
        'password',
        'mobile',
        'gender',
        'date_of_birth',
        'address',
        'bio',
        'social_profiles',
        'avatar',
        'last_ip',
        'device_id',
        'device_type',
        'login_count',
        'phone',
        'last_login',
        'status',
        'is_fake',
        'is_donor',
        'show_as_donor',
        'blood_type',
        'user_role',
        'last_donation_date',
        'latitude',
        'longitude',
        'cover',
        'country',
        'state',
        'workspace',
        'relationship'

    ];

    /**
     * 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',
        'date_of_birth' => 'date',
        'last_login' => 'datetime',
        'deleted_at' => 'datetime',
        'social_profiles' => 'array',
        'status' => 'integer',
        'is_fake' => 'boolean',
    ];

    /**
     * Get the verification request associated with the user.
     */
    public function verificationRequest()
    {
        return $this->hasOne(VerificationRequest::class);
    }

    /**
     * Boot the model.
     *
     * Register the model's event listeners.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        // Event listeners for creating, updating, saving, and deleting
        static::creating(function ($table) {
            if (Auth::check()) {
                $table->created_by = Auth::id();
            }
        });

        static::updating(function ($table) {
            if (Auth::check()) {
                $table->updated_by = Auth::id();
            }
        });

        static::saving(function ($table) {
            if (Auth::check()) {
                $table->updated_by = Auth::id();
            }
        });

        static::deleting(function ($table) {
            if (Auth::check()) {
                $table->deleted_by = Auth::id();
            }
            $table->save();
        });
    }


    /**
     * Relationships and Accessors
     */

    public function providers()
    {
        return $this->hasMany('App\Models\UserProvider');
    }

    public function getRolesListAttribute()
    {
        return array_map('intval', $this->roles->pluck('id')->toArray());
    }

    public function friends()
    {
        return $this->hasMany(Friend::class, 'user_id', 'id');
    }

    public static function getFriends($userId)
    {
        return User::whereIn('id', function ($query) use ($userId) {
            $query->select('friend_two')
                ->from('friends')
                ->where('friend_one', $userId)
                ->where('status', 1);
        })
            ->orWhereIn('id', function ($query) use ($userId) {
                $query->select('friend_one')
                    ->from('friends')
                    ->where('friend_two', $userId)
                    ->where('status', 1);
            })
            ->get();
    }

    public function followers()
    {
        return $this->hasMany(Follower::class, 'following_id', 'id');
    }

    // public function bloodDonation()
    // {
    //     return $this->hasOne(BloodDonation::class, 'user_id', 'id');
    // }

    /**
     * Accessor for Avatar URL
     */
    public function getAvatarUrlAttribute()
    {
        return $this->avatar ? asset('storage/' . $this->avatar) : null;
    }

    /**
     * Accessor for Cover Photo URL
     */
    public function getCoverUrlAttribute()
    {
        return $this->cover ? asset('storage/' . $this->cover) : null;
    }

    public function isBlockedBy($userId)
    {
        return Block::where('blocked', $this->id)
            ->where('blocker', $userId)
            ->exists();
    }

    public function pageLikes()
    {
        return $this->hasMany(\App\Models\PageLike::class, 'user_id');
    }

    public function hasLikedPage($pageId)
    {
        return $this->pageLikes()->where('page_id', $pageId)->exists();
    }

    public function bloodDonations()
    {
        return $this->hasMany(BloodDonation::class);
    }

    public function bloodRequests()
    {
        return $this->hasMany(BloodRequest::class);
    }

    public function driveRegistrations()
    {
        return $this->hasMany(DriveRegistration::class);
    }

    public function getCompletedDonationsCountAttribute()
    {
        return $this->bloodDonations()->where('status', 'completed')->count();
    }

    public function getDaysSinceLastDonationAttribute()
    {
        if (!$this->last_donation_date) {
            return null;
        }

        return $this->last_donation_date->diffInDays(now());
    }

    public function isEligibleToDonate()
    {
        // If never donated before, user is eligible
        if (!$this->last_donation_date) {
            return true;
        }

        // Check if 56 days (8 weeks) have passed since last donation
        return $this->last_donation_date->diffInDays(now()) >= 56;
    }

    /**
     * Get the number of unread pokes for the user
     */
    public function getUnreadPokesCountAttribute()
    {
        return $this->hasMany(Poke::class, 'receiver_id')
            ->where('is_read', false)
            ->count();
    }
    /**
     * Get all pokes received by the user
     */
    public function receivedPokes()
    {
        return $this->hasMany(Poke::class, 'receiver_id');
    }

    /**
     * Get all pokes sent by the user
     */
    public function sentPokes()
    {
        return $this->hasMany(Poke::class, 'sender_id');
    }


    public function getNearbyDonors($bloodType = null, $distance = 10)
    {
        $query = User::where('is_donor', true)
            ->where('show_as_donor', true)
            ->where('id', '!=', $this->id);

        if ($bloodType) {
            $query->where('blood_type', $bloodType);
        }

        if ($this->latitude && $this->longitude) {
            $query->selectRaw("*, (
                6371 * acos(
                    cos(radians(?)) * cos(radians(latitude)) * cos(radians(longitude) - radians(?)) + 
                    sin(radians(?)) * sin(radians(latitude))
                )
            ) AS distance", [$this->latitude, $this->longitude, $this->latitude])
                ->having('distance', '<=', $distance)
                ->orderBy('distance');
        }

        return $query->get();
    }

    // In your User model

    /**
     * Get unread notifications count
     */
    public function getUnreadNotificationsCountAttribute()
    {
        return $this->receivedNotifications()->where('seen', false)->count();
    }

    /**
     * Get received notifications
     */
    public function receivedNotifications()
    {
        return $this->hasMany(Notification::class, 'to_user_id');
    }

    /**
     * Get sent notifications
     */
    public function sentNotifications()
    {
        return $this->hasMany(Notification::class, 'from_user_id');
    }

    /**
     * Get recent unread notifications
     */
    public function getRecentUnreadNotificationsAttribute()
    {
        return $this->receivedNotifications()
            ->where('seen', false)
            ->with('sender')
            ->latest()
            ->limit(5)
            ->get();
    }

    /**
     * Get the user's wallet.
     */
    public function wallet()
    {
        return $this->hasOne(Wallet::class);
    }

    /**
     * Get the user's transactions.
     */
    public function transactions()
    {
        return $this->hasMany(Transaction::class);
    }

    /**
     * Get the user's withdrawal requests.
     */
    public function withdrawalRequests()
    {
        return $this->hasMany(WithdrawalRequest::class);
    }

    /**
     * Get the user's action counts.
     */
    public function actionCounts()
    {
        return $this->hasMany(UserActionCount::class);
    }

    public function metadata()
    {
        return $this->hasMany(UserMetadata::class);
    }

    public function getMeta($key, $default = null)
    {
        $meta = $this->metadata()->where('meta_key', $key)->first();
        return $meta ? $meta->meta_value : $default;
    }

    public function setMeta($key, $value)
    {
        $this->metadata()->updateOrCreate(
            ['meta_key' => $key],
            ['meta_value' => $value]
        );
        return $this;
    }

    public function getAllMeta()
    {
        return $this->metadata->pluck('meta_value', 'meta_key')->toArray();
    }
    public function usershortInfo($id, $loggedInUserId = 0)
    {
        $user = $this->select(['id', 'first_name', 'last_name', 'avatar'])->where('id', $id)->first();
        if (!empty($user)) {
            return [
                'id' => $user->id,
                'username' => $user->username,
                'first_name' => $user->first_name,
                'last_name' => $user->last_name,
                'avatar' => $user->avatar ? getMedia($user->avatar) : asset("img/placeholder/default-avatar.jpg"),
                'cover' => $user->cover ? getMedia($user->cover) : asset("img/placeholder/default-avatar.jpg")
            ];
        }
        return null;
    }
    public function scopeNearbyUsers($query, $latitude, $longitude, $radius = 20)
    {
        return $query->selectRaw(
            "
            id,username, first_name, last_name, avatar, latitude, longitude,
            (6371 * acos(cos(radians(?))
            * cos(radians(latitude))
            * cos(radians(longitude) - radians(?))
            + sin(radians(?))
            * sin(radians(latitude)))) AS distance",
            [$latitude, $longitude, $latitude]
        )
            ->where('id', '!=', Auth::id())
            ->having('distance', '<', $radius)
            ->orderBy('distance', 'asc');
    }

    /**
     * Check if the user is an admin
     *
     * @return bool
     */
    public function isAdmin()
    {
        return $this->user_role === 'admin';
    }

    /**
     * Check if the user is a regular user
     *
     * @return bool
     */
    public function isUser()
    {
        return $this->user_role === 'user';
    }
}
