<?php

namespace App\Models;

use App\Enums\PlanStatus;
use App\Enums\UserRoles;
use App\Enums\UserStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Support\Str;
use Carbon\Carbon;
use DB;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'role',
        'type',
        'username',
        'firstname',
        'lastname',
        'email',
        'password',
        'phone',
        'currency',
        'crypto_currency',
        'address',
        'city',
        'state',
        'country',
        'zipcode',
        'email_verify',
        'email_verified_at',
        'verification_front',
        'verification_back',
        'kyc_verify',
        'referred_by',
        'ip_address',
        'mac_address',
        'act_session',
        'status',
        'signal',
        'hold_message',
        'last_login_at',
        'password_changed_at',
        'registered_at' 
    ];

    protected $cast = [
        'email_verify' => 'boolean',
    ];

    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 [];
    }

    /**
     * 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',
        'last_login' => 'datetime',
        'last_login_at' => 'datetime',
        'registered_at' => 'datetime',
        'password_changed_at' => 'datetime',
        'password' => 'hashed',
        'role' => UserRoles::class,
        'status' => UserStatus::class,
    ];

    /**
     * Boot method to set default values
     */
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($user) {
            if (!$user->registered_at) {
                $user->registered_at = now();
            }
            if (!$user->status) {
                $user->status = UserStatus::INACTIVE;
            }
            if (!$user->role) {
                $user->role = UserRoles::USER;
            }
        });
    }

    /*
    |--------------------------------------------------------------------------
    | Email Verification Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Check if email exists in database
     * 
     * @param string $email
     * @return bool
     */
    public static function emailExists(string $email): bool
    {
        return self::where('email', $email)->exists();
    }

    /**
     * Check if user email is verified
     * 
     * @return bool
     */
    public function hasVerifiedEmail(): bool
    {
        return !is_null($this->email_verified_at) || $this->email_verify === 'yes';
    }

    /**
     * Mark email as verified
     * 
     * @return bool
     */
    public function markEmailAsVerified(): bool
    {
        return $this->forceFill([
            'email_verified_at' => $this->freshTimestamp(),
            'email_verify' => 'yes',
            'status' => UserStatus::ACTIVE,
        ])->save();
    }

    /*
    |--------------------------------------------------------------------------
    | Username Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Check if username exists in database
     * 
     * @param string $username
     * @return bool
     */
    public static function usernameExists(string $username): bool
    {
        return self::where('username', $username)->exists();
    }

    /**
     * Generate a unique username
     * 
     * @param string $name
     * @return string
     */
    public static function generateUniqueUsername(string $name = ""): string
    {
        $base = $name ? Str::slug($name) : 'user';
        $suffixLength = $name ? 4 : 8;

        do {
            $suffix = Str::random($suffixLength);
            $username = "{$base}-{$suffix}";
        } while (self::usernameExists($username));

        return $username;
    }

    /**
     * Get user by username
     * 
     * @param string $username
     * @return User|null
     */
    public static function findByUsername(string $username): ?self
    {
        return self::where('username', $username)->first();
    }

    /**
     * Get user by email
     * 
     * @param string $email
     * @return User|null
     */
    public static function findByEmail(string $email): ?self
    {
        return self::where('email', $email)->first();
    }

    /*
    |--------------------------------------------------------------------------
    | Status & Role Methods
    |--------------------------------------------------------------------------
    */

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

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

    /**
     * Check if user is disabled
     * 
     * @return bool
     */
    public function isDisabled(): bool
    {
        return $this->status === UserStatus::DISABLED;
    }

    /**
     * Check if user is under review
     * 
     * @return bool
     */
    public function isUnderReview(): bool
    {
        return $this->status === UserStatus::REVIEW;
    }

    /**
     * Check if user is suspended
     * 
     * @return bool
     */
    public function isSuspended(): bool
    {
        return $this->status === UserStatus::SUSPENDED;
    }

    /**
     * Check if user can login
     * 
     * @return bool
     */
    public function canLogin(): bool
    {
        return $this->isActive() && $this->hasVerifiedEmail();
    }

    /**
     * Check if user is admin
     * 
     * @return bool
     */
    public function isAdmin(): bool
    {
        return $this->role === UserRoles::ADMIN;
    }

    /**
     * Check if user is regular user
     * 
     * @return bool
     */
    public function isUser(): bool
    {
        return $this->role === UserRoles::USER;
    }

    /*
    |--------------------------------------------------------------------------
    | Login & Activity Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Update login metadata (last login, IP, MAC address)
     * 
     * @return bool
     */
    public function updateLoginMetadata(): bool
    {
        return $this->update([
            'last_login' => Carbon::now(),
            'last_login_at' => Carbon::now(),
            'ip_address' => request()->ip(),
            'mac_address' => get_mac_address(),
        ]);
    }

    /**
     * Get days since last login
     * 
     * @return int|null
     */
    public function daysSinceLastLogin(): ?int
    {
        return $this->last_login ? $this->last_login->diffInDays(now()) : null;
    }

    /**
     * Check if user is online (logged in within last 15 minutes)
     * 
     * @return bool
     */
    public function isOnline(): bool
    {
        if (!$this->last_login) {
            return false;
        }
        
        return $this->last_login->greaterThan(now()->subMinutes(15));
    }

    /*
    |--------------------------------------------------------------------------
    | Name & Display Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Get full name
     * 
     * @return string
     */
    public function getFullNameAttribute(): string
    {
        return trim("{$this->firstname} {$this->lastname}");
    }

    /**
     * Get display name (full name or username)
     * 
     * @return string
     */
    public function getDisplayNameAttribute(): string
    {
        return $this->full_name ?: $this->username;
    }

    /**
     * Get initials
     * 
     * @return string
     */
    public function getInitialsAttribute(): string
    {
        $firstname = $this->firstname ? substr($this->firstname, 0, 1) : '';
        $lastname = $this->lastname ? substr($this->lastname, 0, 1) : '';
        
        return strtoupper($firstname . $lastname) ?: strtoupper(substr($this->username, 0, 2));
    }

    public function activePlans(){
        return $this->plans()->where('status' , PlanStatus::ACTIVE->value);
    }

    /*
    |--------------------------------------------------------------------------
    | Referral Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Get the user who referred this user
     * 
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function referrer()
    {
        return $this->belongsTo(User::class, 'referred_by');
    }

    /**
     * Get users referred by this user
     * 
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function referrals()
    {
        return $this->hasMany(User::class, 'referred_by');
    }

    /**
     * Get count of active referrals
     * 
     * @return int
     */
    public function getActiveReferralsCount(): int
    {
        return $this->referrals()->where('status', UserStatus::ACTIVE)->count();
    }

    /**
     * Check if user was referred
     * 
     * @return bool
     */
    public function wasReferred(): bool
    {
        return !is_null($this->referred_by);
    }

    /*
    |--------------------------------------------------------------------------
    | Scopes
    |--------------------------------------------------------------------------
    */

    /**
     * Scope to get only active users
     */
    public function scopeActive($query)
    {
        return $query->where('status', UserStatus::ACTIVE);
    }

    /**
     * Scope to get only verified users
     */
    public function scopeVerified($query)
    {
        return $query->whereNotNull('email_verified_at')
            ->orWhere('email_verify', 'yes');
    }

    /**
     * Scope to get users by role
     */
    public function scopeByRole($query, $role)
    {
        return $query->where('role', $role);
    }

    /**
     * Scope to get recently registered users
     */
    public function scopeRecentlyRegistered($query, $days = 7)
    {
        return $query->where('registered_at', '>=', now()->subDays($days));
    }

    /**
     * Scope to get inactive users
     */
    public function scopeInactive($query, $days = 30)
    {
        return $query->where('last_login', '<', now()->subDays($days))
            ->orWhereNull('last_login');
    }

    /*
    |--------------------------------------------------------------------------
    | Relationships
    |--------------------------------------------------------------------------
    */

    /**
     * Get user's transactions
     */
    public function account()
    {
        return $this->hasOne(UserBalance::class);
    }

     public function watchlist()
    {
        return $this->hasOne(Watchlist::class);
    }

    public function mining()
    {
        return $this->hasOne(UserMining::class);
    }

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

    public function orders()
    {
        return $this->hasMany(Order::class);
    }
    
    public function plans() {
        return $this->hasMany(UserPlan::class);
    }

    
    /**
     * Get user's portfolios
     */
    public function portfolios()
    {
        return $this->hasMany(Portfolio::class);
    }

    /**
     * Get user's trades
     */
    public function trades()
    {
        return $this->hasMany(Trade::class);
    }

    /**
     * Get user's wallets
     */
    public function wallets()
    {
        return $this->hasMany(Wallet::class);
    }

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

    /*
    |--------------------------------------------------------------------------
    | Helper Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Activate user account
     * 
     * @return bool
     */
    public function activate(): bool
    {
        return $this->update(['status' => UserStatus::ACTIVE]);
    }

    /**
     * Deactivate user account
     * 
     * @return bool
     */
    public function deactivate(): bool
    {
        return $this->update(['status' => UserStatus::INACTIVE]);
    }

    /**
     * Suspend user account
     * 
     * @return bool
     */
    public function suspend(): bool
    {
        // Revoke all tokens
        $this->tokens()->delete();
        
        return $this->update(['status' => UserStatus::SUSPENDED]);
    }

    /**
     * Disable user account
     * 
     * @return bool
     */
    public function disable(): bool
    {
        // Revoke all tokens
        $this->tokens()->delete();
        
        return $this->update(['status' => UserStatus::DISABLED]);
    }

    /**
     * Get user status label
     * 
     * @return string
     */
    public function getStatusLabelAttribute(): string
    {
        return match($this->status) {
            UserStatus::ACTIVE => 'Active',
            UserStatus::INACTIVE => 'Inactive',
            UserStatus::DISABLED => 'Disabled',
            UserStatus::REVIEW => 'Under Review',
            UserStatus::SUSPENDED => 'Suspended',
            default => 'Unknown'
        };
    }

    /**
     * Get user role label
     * 
     * @return string
     */
    public function getRoleLabelAttribute(): string
    {
        return match($this->role) {
            UserRoles::ADMIN => 'Administrator',
            UserRoles::USER => 'User',
            default => 'Unknown'
        };
    }

    /**
     * Check if account needs verification
     * 
     * @return bool
     */
    public function needsVerification(): bool
    {
        return !$this->hasVerifiedEmail();
    }

    /**
     * Get account age in days
     * 
     * @return int
     */
    public function getAccountAgeInDays(): int
    {
        return $this->registered_at ? $this->registered_at->diffInDays(now()) : 0;
    }

    

    public function updateEmail(array $data): void
    {
        $this->update([
            'email' => $data['email'] ?? $this->email,
        ]);
    }

    
    public function updatePassword(array $data): void
    {
        $this->update([
            'password' => $data['password'] ?? $this->password,
        ]);
    }
    public function updateAddress(array $data): void
    {
        $this->update([
            'address' => $data['street_address'] ?? $this->address,
            'city' => $data['city'] ?? $this->city,
            'state' => $data['state'] ?? $this->state,
            'country' => $data['country'] ?? $this->country,
            'zipcode' => $data['post_code'] ?? $this->zipcode,
        ]);
    }
    
    public static function get_all_user($limit)
    {
        return self::where('role', 'user')
            ->orderBy('created_at', 'desc')
            ->paginate($limit);
    }

    public static function get_all_count()
    {
        $total_all = DB::table('users')
            ->where('role', 'user')
            ->count();
        return $total_all;
    }

    public static function get_active_count()
    {
        $total_pending = DB::table('users')
            ->where('role', 'user')
            ->where('status', 'active')
            ->count();
        return $total_pending;
    }

    public static function get_inactive_count()
    {
        $total_pending = DB::table('users')
            ->where('role', 'user')
            ->where('status', 'inactive')
            ->count();
        return $total_pending;
    }

    public static function get_disabled_count()
    {
        $total_pending = DB::table('users')
            ->where('role', 'user')
            ->where('status', 'disabled')
            ->count();
        return $total_pending;
    }
}