<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Log;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'login',
        'promo_code',
        'date_of_birth',
        'phone_number',
        'manager_id',
    ];

    /**
     * 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',
    ];

    protected static function booted()
    {
        static::created(function ($user) {
            // Find the first unassigned address
            $unassignedAddress = Address::whereNull('user_id')->first();
            
            if ($unassignedAddress) {
                $unassignedAddress->update(['user_id' => $user->id]);
            }

            // Assign the 'user' role
            $userRole = Role::where('name', 'user')->first();
            if ($userRole) {
                $user->roles()->attach($userRole->id);
            }
        });
    }

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class);
    }

    public function hasRole(string $role): bool
    {
        return $this->roles()->where('name', $role)->exists();
    }

    public function hasPermission(string $permission): bool
    {
        return $this->roles->contains(function ($role) use ($permission) {
            return $role->hasPermission($permission);
        });
    }

    public function isAdmin(): bool
    {
        return $this->hasRole('admin');
    }

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

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

    public function getWalletAddress()
    {
        return $this->address?->address;
    }

    public function confirmedBalance()
    {
        $positive = Transaction::where('user_id', $this->id)->where(function ($query) {
            $query->where('type', 'deposit')
                ->orWhere('type', 'close_position');
        })->where('confirmed', 1)->sum('amount');

        $negative = Transaction::where('user_id', $this->id)->where(function ($query) {
            $query->where('type', 'withdraw');
        })->where('confirmed', 1)->sum('amount');

        return round($positive - $negative, 2);
    }

    /**
     * Calculate the total margin from all open orders
     *
     * @return float
     */
    public function calculateTotalMargin()
    {
        return $this->orders()
            ->where('status', 'open')
            ->sum('margin');
    }

    /**
     * Get the formatted total margin
     *
     * @return string
     */
    public function getFormattedTotalMargin()
    {
        return number_format($this->calculateTotalMargin(), 2);
    }

    /**
     * Calculate the free margin (balance - total margin)
     *
     * @return float
     */
    public function calculateFreeMargin()
    {
        $balance = $this->confirmedBalance();
        $totalMargin = $this->calculateTotalMargin();
        
        return max(0, $balance - $totalMargin);
    }

    /**
     * Get the formatted free margin
     *
     * @return string
     */
    public function getFormattedFreeMargin()
    {
        return number_format($this->calculateFreeMargin(), 2);
    }

    /**
     * Calculate the margin level (equity / margin * 100)
     *
     * @return float
     */
    public function calculateMarginLevel()
    {
        $totalMargin = $this->calculateTotalMargin();
        if ($totalMargin <= 0) {
            return 0;
        }

        $equity = $this->confirmedBalance() + $this->calculateTotalUnrealizedPL();
        return ($equity / $totalMargin) * 100;
    }

    /**
     * Get the formatted margin level
     *
     * @return string
     */
    public function getFormattedMarginLevel()
    {
        return number_format($this->calculateMarginLevel(), 2) . '%';
    }

    /**
     * Calculate the total unrealized profit/loss from all open orders
     *
     * @param bool $includeFees Whether to include fees in the calculation
     * @param bool $asPercentage Whether to return the result as a percentage
     * @return float
     */
    public function calculateTotalUnrealizedPL($includeFees = false, $asPercentage = false)
    {
        $totalPL = 0;
        $totalInitialValue = 0;

        $openOrders = $this->orders()->where('status', 'open')->where('user_id', $this->id)->get();

        foreach ($openOrders as $order) {
            $pl = $order->calculateUnrealizedPL(false, false);
            $totalPL += $pl;
            
            if ($asPercentage) {
                $initialValue = $order->open_price * $order->volume;
                $totalInitialValue += $initialValue;
            }
        }

        if ($asPercentage && $totalInitialValue != 0) {
            return ($totalPL / $totalInitialValue) * 100;
        }

        return $totalPL;
    }

    /**
     * Get the formatted total unrealized P/L
     *
     * @param bool $includeFees Whether to include fees in the calculation
     * @param bool $asPercentage Whether to return the result as a percentage
     * @return string
     */
    public function getFormattedTotalUnrealizedPL($includeFees = true, $asPercentage = false)
    {
        $pl = $this->calculateTotalUnrealizedPL($includeFees, $asPercentage);
        
        if ($asPercentage) {
            return number_format($pl, 2) . '%';
        }

        return number_format($pl, 2);
    }

    /**
     * Get the CSS class for the total P/L status
     *
     * @return string
     */
    public function getTotalPLStatus()
    {
        $pl = $this->calculateTotalUnrealizedPL();
        
        if ($pl > 0) {
            return 'text-success';
        } elseif ($pl < 0) {
            return 'text-danger';
        } else {
            return 'text-secondary';
        }
    }

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

    public function sessions(): HasMany
    {
        return $this->hasMany(UserSession::class);
    }

    public function isOnline(): bool
    {
        $lastSession = $this->sessions()->orderByDesc('login_at')->first();
        if (!$lastSession) return false;
        // Online if no logout and last activity within 5 minutes
        return is_null($lastSession->logout_at)
            && $lastSession->last_activity_at
            && $lastSession->last_activity_at->gt(now()->subMinutes(5));
    }

    public function isManager(): bool
    {
        return $this->hasRole('manager');
    }

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

    public function managedUsers()
    {
        return $this->hasMany(User::class, 'manager_id');
    }

    public function scopeManagedBy($query, User $manager)
    {
        return $query->where('manager_id', $manager->id);
    }

    public function scopeWithManagedUsers($query)
    {
        return $query->whereHas('roles', function ($query) {
            $query->where('name', 'manager');
        });
    }

    public function getManagedUsersOrders()
    {
        return Order::whereIn('user_id', $this->managedUsers()->pluck('id'));
    }
}
