<?php

namespace App\Models;

use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;

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

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'username',
        'password',
        'fullname',
        'telephone',
        'email',
        'status',
        'current_session_id',
        'last_login_at',
        'last_login_ip',
        'last_login_device',
        'flag_backdate_so',
        'delete_flag',
        'created_at',
        'updated_at',
        'created_by',
        'updated_by',
        'f_need_change_password'
    ];

    public function creator()
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function modificator()
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    /**
     * Many-to-many relationship with stores
     * User can be assigned to multiple stores
     */
    public function stores()
    {
        return $this->belongsToMany(Store::class, 'users_stores', 'user_id', 'store_id')
            ->withTimestamps()
            ->withPivot(['created_by', 'updated_by']);
    }

    /**
     * Get array of store IDs that user has access to
     * 
     * @return array
     */
    public function getAccessibleStoreIds()
    {
        return $this->stores()->pluck('m_stores.id')->toArray();
    }

    /**
     * Check if user has access to specific store
     * 
     * @param int $storeId
     * @return bool
     */
    public function hasAccessToStore($storeId)
    {
        return $this->stores()->where('m_stores.id', $storeId)->exists();
    }


    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'flag_backdate_so' => 'boolean',
        'delete_flag' => 'boolean',
        'f_need_change_password' => 'boolean',
        'last_login_at' => 'datetime',
    ];

    /**
     * Check if user can backdate Stock Opname
     * 
     * @return bool
     */
    public function canBackdateSO()
    {
        return $this->flag_backdate_so === true;
    }

    /**
     * Check if user is active
     * 
     * @return bool
     */
    public function isActive()
    {
        return $this->status === 'Active';
    }

    /**
     * Check if user is inactive
     * 
     * @return bool
     */
    public function isInactive()
    {
        return $this->status === 'Inactive';
    }

    /**
     * Check if user has active session
     * 
     * @return bool
     */
    public function hasActiveSession()
    {
        return !empty($this->current_session_id);
    }

    /**
     * Check if current session matches stored session
     * 
     * @param string $sessionId
     * @return bool
     */
    public function isCurrentSession($sessionId)
    {
        return $this->current_session_id === $sessionId;
    }

    /**
     * Clear user session
     * 
     * @return void
     */
    public function clearSession()
    {
        $this->update([
            'current_session_id' => null
        ]);
    }

    /**
     * Update user session info
     * 
     * @param string $sessionId
     * @param string $ip
     * @param string $userAgent
     * @return void
     */
    public function updateSessionInfo($sessionId, $ip, $userAgent)
    {
        $this->update([
            'current_session_id' => $sessionId,
            'last_login_at' => now(),
            'last_login_ip' => $ip,
            'last_login_device' => $userAgent
        ]);
    }

    /**
     * Always encrypt password when it is updated.
     *
     * @param $value
     * @return string
     */
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = bcrypt($value);
    }
}
