<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Models\TripRequest;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'phone',
        'user_type',
        'service_type',
        'status',
        'notes',
        'is_verified',
        'profile_image',
        'latitude',
        'longitude',
        'vehicle_id',
        'last_login_at',
        'governorate_id',
        'city_id',
        'address',
        'bio',
        'birth_date',
        'account_verified',
        'driver_legal_accepted_at',
        'driver_verification_status',
        'driver_verification_note',
        'vehicle_type',
        'vehicle_color',
        'license_plate',
        'vehicle_model_year',
    ];

    /**
     * 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',
        'is_verified' => 'boolean',
        'account_verified' => 'boolean',
        'driver_legal_accepted_at' => 'datetime',
        'latitude' => 'decimal:8',
        'longitude' => 'decimal:8',
    ];

    /**
     * Get the user's role.
     */
    public function getRoleAttribute()
    {
        return $this->user_type;
    }

    /**
     * Check if user is a driver.
     */
    public function isDriver()
    {
        return $this->user_type === 'driver';
    }

    /**
     * Check if user is a passenger.
     */
    public function isPassenger()
    {
        return $this->user_type === 'passenger';
    }

    /**
     * Check if user is an admin.
     */
    public function isAdmin()
    {
        return $this->user_type === 'admin';
    }

    /**
     * Check if user is a restaurant manager.
     */
    public function isRestaurantManager()
    {
        return $this->user_type === 'restaurant_manager';
    }

    /**
     * Restaurant relationship
     */
    public function restaurant()
    {
        return $this->hasOne(Restaurant::class, 'user_id');
    }

    /**
     * Check if user is a gas manager.
     */
    public function isGasManager()
    {
        return $this->user_type === 'gas_manager';
    }

    /**
     * Check if user is a service manager (restaurant or gas).
     */
    
    public function isServiceManager()
    {
        return in_array($this->user_type, ['restaurant_manager', 'gas_manager']);
    }

    /**
     * Get the vehicle associated with the user.
     */
    public function vehicle()
    {
        return $this->belongsTo(Vehicle::class);
    }

    /**
     * Get the trips where this user is a passenger.
     */
    public function passengerTrips()
    {
        return $this->hasMany(Trip::class, 'passenger_id');
    }

    /**
     * Get the trips where this user is a driver.
     */
    public function driverTrips()
    {
        return $this->hasMany(Trip::class, 'driver_id');
    }

    /**
     * Get all trips for this user (both as passenger and driver).
     */
    public function trips()
    {
        return Trip::where('passenger_id', $this->id)
                   ->orWhere('driver_id', $this->id)
                   ->orderBy('created_at', 'desc');
    }

    /**
     * Get the notifications for this user.
     */
    public function notifications()
    {
        return $this->hasMany(Notification::class);
    }

    /**
     * Get the driver profile for this user.
     */
    public function driver()
    {
        return $this->hasOne(\App\Models\Driver::class);
    }

    /**
     * Get the passenger profile for this user.
     */
    public function passenger()
    {
        return $this->hasOne(\App\Models\Passenger::class);
    }


    /**
     * Get payments where user is a driver.
     */
    public function driverPayments()
    {
        return $this->hasMany(\App\Models\Payment::class, 'driver_id');
    }

    /**
     * Get payments where user is a passenger.
     */
    public function passengerPayments()
    {
        return $this->hasMany(\App\Models\Payment::class, 'passenger_id');
    }

    /**
     * Get all payments for this user (both as driver and passenger).
     */
    public function payments()
    {
        return \App\Models\Payment::where('driver_id', $this->id)
                                 ->orWhere('passenger_id', $this->id);
    }

    /**
     * Get trip requests made by this user (as passenger).
     */
    public function tripRequests()
    {
        return $this->hasMany(TripRequest::class, 'passenger_id');
    }

    /**
     * Get trip requests accepted by this user (as driver).
     */
    public function acceptedTripRequests()
    {
        return $this->hasMany(TripRequest::class, 'driver_id');
    }

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

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

    /**
     * Get referrals made by this user.
     */
    public function referrals()
    {
        return $this->hasMany(Referral::class, 'referrer_id');
    }

    /**
     * Get referrals received by this user.
     */

    public function referredBy()
    {
        return $this->hasMany(Referral::class, 'referred_id');
    }

    /**
     * Get referral earnings for this user (as referrer).
     */
    public function referralEarnings()
    {
        return $this->hasMany(ReferralEarning::class, 'referrer_id');
    }

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

    /**
     * Get or create wallet for user.
     */
    public function getOrCreateWallet()
    {
        return $this->wallet ?? Wallet::getOrCreateForUser($this->id);
    }

    /**
     * Get wallet transactions.
     */
    public function walletTransactions()
    {
        return $this->hasManyThrough(WalletTransaction::class, Wallet::class);
    }

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

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

    /**
     * Get food orders for this user (as customer).
     */
    public function foodOrders()
    {
        return $this->hasMany(FoodOrder::class, 'customer_id');
    }

    /**
     * Get food orders for this user (as driver).
     */
    public function driverFoodOrders()
    {
        return $this->hasMany(FoodOrder::class, 'driver_id');
    }

    /**
     * Get the governorate that the user belongs to.
     */
    public function governorate()
    {
        return $this->belongsTo(Governorate::class);
    }

    /**
     * Get the city that the user belongs to.
     */
    public function city()
    {
        return $this->belongsTo(City::class);
    }

    /**
     * Get or create user points.
     */
    public function getOrCreatePoints()
    {
        return $this->points ?? UserPoints::getOrCreateForUser($this->id);
    }

    /**
     * Add points to user.
     */
    public function addPoints($points, $description = null, $source = null, $metadata = null)
    {
        $userPoints = $this->getOrCreatePoints();
        $userPoints->addPoints($points, $description, $source, $metadata);
    }

    /**
     * Use points from user.
     */
    public function usePoints($points, $description = null, $metadata = null)
    {
        $userPoints = $this->getOrCreatePoints();
        $userPoints->usePoints($points, $description, $metadata);
    }

    /**
     * Get available points.
     */
    public function getAvailablePoints()
    {
        return $this->getOrCreatePoints()->available_points;
    }
}
