<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;

class User extends Authenticatable
{
    use HasFactory;

    const ROLES = [
        ['name' => 'Propriétaire', 'id' => 'owner', 'slug' => 'owner'],
        ['name' => 'Administrateur', 'id' => 'admin', 'slug' => 'admin'],
        ['name' => 'Caissier', 'id' => 'cashier', 'slug' => 'cashier'],
        ['name' => 'Gestionnaire de Stock', 'id' => 'stock_manager', 'slug' => 'stock_manager'],
    ];

    // use HasApiTokens;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $guarded = [];

    const STATUS_INACTIVE = false;
    const STATUS_ACTIVE = true;

    const GENDER_MALE = 1;
    const GENDER_FEMALE = 2;
    const PREFER_NOT_TO_SAY = 3;

    public function getRouteKeyName()
    {
        return 'username';
    }

    /**
     * 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',
            'phone_verified_at' => 'datetime',
            'birth_date' => 'date',
            'otp_expires_at' => 'datetime',
            'last_login_at' => 'datetime',
            'locked_until' => 'datetime',
            'created_at' => 'datetime',
            'updated_at' => 'datetime',
            'password' => 'hashed',
            'status' => 'boolean',
        ];
    }

    public static function generateUniqueUsername(string $name): string
    {
        $usernameBase = preg_replace('/\s+/', '_', strtolower($name));
        $username = $usernameBase . '_' . random_int(10000, 99999);
        $usernames = User::where('username', $username)->get();
        while ($usernames->count() > 0) {
            $username .= '_' . random_int(0, 9);
            $usernames = User::where('username', $username)->get();
        }

        return $username;
    }

    public function address()
    {
        return $this->belongsTo(Address::class);
    }

    public function getProvinceAttribute()
    {
        $address = $this->address;
        if (! $address) {
            return 'N/A';
        }
        if (! $address->province_id) {
            return 'N/A';
        }
        if ($province = Province::find($address->province_id)) {
            return $province->name;
        }
        return 'N/A';
    }

    public function getCityAttribute()
    {
        $address = $this->address;
        if (! $address) {
            return 'N/A';
        }
        if (! $address->city_id) {
            return 'N/A';
        }
        if ($city = City::find($address->city_id)) {
            return $city->name;
        }
        return 'N/A';
    }

    public function getStatusName()
    {
        if ($this->status) {
            return 'actif';
        }
        else {
            return 'inactif';
        }
    }

    public function getGenderName()
    {
        if (! $this->gender) {
            return 'N/A';
        }

        return match ($this->gender) {
            self::GENDER_MALE => 'M',
            self::GENDER_FEMALE => 'F',
            default => 'N/A',
        };
    }

    public function isOwner()
    {
        return $this->role === 'owner';
    }

    public function isAdmin()
    {
        return $this->role === 'admin';
    }

    public function isCashier()
    {
        return $this->role === 'cashier';
    }

    public function isStockManager()
    {
        return $this->role === 'stock_manager';
    }
    
    public function admin()
    {
        return $this->hasOne(Admin::class);
    }


    public function subscriptions()
    {
        return $this->hasMany(Subscription::class);
    }

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

    public function sales()
    {
        return $this->hasMany(Sale::class, 'user_id');
    }

    public function activityLogs()
    {
        return $this->hasMany(ActivityLog::class);
    }

    public function getStatusBadgeAttribute()
    {
        return match ($this->status) {
            true => '<span class="inline-block px-3 py-1 border border-green-500 bg-green-100 text-xs font-medium rounded text-green-700 text-center min-w-30"> <i class="ph ph-check-circle mr-1"></i>Actif</span>',
            false => '<span class="inline-block px-3 py-1 border border-red-500 bg-red-100 text-xs font-medium rounded text-red-700 text-center min-w-30"> <i class="ph ph-x-circle mr-1"></i>Inactif</span>',
        };
    }

    public function getRoleBadgeAttribute()
    {
        return match ($this->role) {
            'owner' => '<span class="inline-block px-3 py-1 border border-purple-500 bg-purple-100 text-xs font-medium rounded text-purple-700 text-center min-w-30"> <i class="ph ph-crown mr-1"></i>Propriétaire</span>',
            'admin' => '<span class="inline-block px-3 py-1 border border-blue-500 bg-blue-100 text-xs font-medium rounded text-blue-700 text-center min-w-30"> <i class="ph ph-user-circle mr-1"></i>Administrateur</span>',
            'cashier' => '<span class="inline-block px-3 py-1 border border-green-500 bg-green-100 text-xs font-medium rounded text-green-700 text-center min-w-30"> <i class="ph ph-cash-register mr-1"></i>Caissier</span>',
            'stock_manager' => '<span class="inline-block px-3 py-1 border border-orange-500 bg-orange-100 text-xs font-medium rounded text-orange-700 text-center min-w-30"> <i class="ph ph-warehouse mr-1"></i>Gestionnaire de Stock</span>',
            default => '<span class="inline-block px-3 py-1 border border-gray-500 bg-gray-100 text-xs font-medium rounded text-gray-700 text-center min-w-30"> <i class="ph ph-x-circle mr-1"></i>Inconnu</span>',
        };
    }

    public function getRoleNameAttribute()
    {
        return match ($this->role) {
            'owner' => 'Propriétaire',
            'admin' => 'Administrateur',
            'cashier' => 'Caissier',
            'stock_manager' => 'Gestionnaire de Stock',
            default => 'Inconnu',
        };
    }
    
    public function getStatusLabelAttribute()
    {
        return match ($this->status) {
            self::STATUS_ACTIVE => 'Actif',
            self::STATUS_INACTIVE => 'Inactif',
            default => 'Inconnu',
        };
    }

    public function getFullNameAttribute()
    {
        return $this->firstname ? $this->firstname . ' ' . $this->lastname : $this->lastname;
    }


    public function loginUser($remember = false)
    {
        // Check if account is locked
        if ($this->isLocked()) {
            return false;
        }

        // Clear any existing sessions for this user
        if (config('session.driver') === 'database') {
            DB::table('sessions')->where('user_id', $this->id)->delete();
        }

        // Regenerate session to prevent CSRF issues
        session()->regenerate();

        // Set session data
        session([
            'auth_user_id' => $this->id,
            'auth_token' => $this->api_token,
        ]);

        // Reset failed login attempts on successful login
        $this->update([
            'failed_login_attempts' => 0,
            'locked_until' => null,
            'last_login_at' => now(),
        ]);

        Auth::login($this, $remember);

        return true;
    }

    /**
     * Check if account is locked
     */
    public function isLocked(): bool
    {
        return $this->locked_until && $this->locked_until->isFuture();
    }

    /**
     * Increment failed login attempts
     */
    public function incrementFailedLoginAttempts(): void
    {
        $this->increment('failed_login_attempts');
        
        // Lock account after 5 failed attempts for 15 minutes
        if ($this->failed_login_attempts >= 5) {
            $this->update(['locked_until' => now()->addMinutes(15)]);
        }
    }

    /**
     * Get lockout message
     */
    public function getLockoutMessage(): string
    {
        if (!$this->isLocked()) {
            return '';
        }
        
        $minutes = $this->locked_until->diffInMinutes(now());
        return "Compte verrouillé. Réessayez dans {$minutes} minutes.";
    }
}