<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use Illuminate\Support\Facades\Cache;
use App\Observers\UserObserver;
use App\Models\Plan;
use App\Models\Advertisement;
use App\Models\Trade;
use App\Models\Dispute;
use App\Models\Review;
use App\Models\BillPayment;
use App\Models\Savings;
use App\Models\SavingsInterestLog;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'otp_code',
        'email',
        'role',
        'pin',
        'username',
        'sudo_id',
        'balance',
        'address',
        'city',
        'state',
        'country',
        'photo',
        'gender',
        'email_verified_at',
        'phone',
        'dob',
        'password',
        'kyc_verified_at',
        'referred_by',
        'status',
        'loser_mode',
        'g2fa',
        'g2fa_secret',
        'staked',
        'rating',
        'completed_trades',
        'is_admin',
        'last_seen_at',
        'ip_address',
        'fee_paid',
        'coupon',
        'signup_bonus_at',
        'first_deposit_bonus_at',
    ];

    /**
     * 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',
        'kyc_verified_at' => 'datetime',
        'rating' => 'decimal:2',
        'is_admin' => 'boolean',
        'last_seen_at' => 'datetime',
        'signup_bonus_at' => 'datetime',
        'first_deposit_bonus_at' => 'datetime',
    ];
    
    
    
    // P2P Relationships
    public function advertisements()
    {
        return $this->hasMany(Advertisement::class);
    }

    public function buyTrades()
    {
        return $this->hasMany(Trade::class, 'buyer_id');
    }

    public function sellTrades()
    {
        return $this->hasMany(Trade::class, 'seller_id');
    }

    public function allTrades()
    {
        return Trade::where('buyer_id', $this->id)->orWhere('seller_id', $this->id);
    }

    public function complainantDisputes()
    {
        return $this->hasMany(Dispute::class, 'complainant_id');
    }

    public function respondentDisputes()
    {
        return $this->hasMany(Dispute::class, 'respondent_id');
    }

    public function givenReviews()
    {
        return $this->hasMany(Review::class, 'reviewer_id');
    }

    public function receivedReviews()
    {
        return $this->hasMany(Review::class, 'reviewed_id');
    }

    public function resolvedDisputes()
    {
        return $this->hasMany(Dispute::class, 'resolved_by');
    }

    // Helper methods
    public function updateRating()
    {
        $averageRating = $this->receivedReviews()->avg('rating');
        $this->update(['rating' => $averageRating ?? 0]);
    }

    public function isOnline()
    {
        return $this->last_seen_at && $this->last_seen_at->diffInMinutes(now()) < 5;
    }

    /**
     * Get the KYC records associated with the user.
     */
    public function kycRecords()
    {
        return $this->hasMany(KycRecord::class);
    }



    //get deposits
    public function deposits()
    {
        return $this->hasMany(Deposit::class);
    }

    //get withdrawals
    public function withdrawals()
    {
        return $this->hasMany(Withdrawal::class);
    }

    //get transactions
    public function transactions()
    {
        return $this->hasMany(Transaction::class);
    }

    //get bot activations
    public function botActivations()
    {
        return $this->hasMany(BotActivation::class);
    }

    //bot trading history
    public function botHistory()
    {
        return $this->hasMany(BotHistory::class);
    }


    // define relationship with autowallets
    public function autoWallets()
    {
        return $this->hasMany(AutoWallet::class);
    }

    // define relationship with west wallets
    public function westWallets()
    {
        return $this->hasMany(WestWallet::class);
    }

    // define relationship with west wallet transactions
    public function westWalletTransactions()
    {
        return $this->hasMany(WestWalletTransaction::class);
    }

    /**
     * Get the cached user model by ID.
     *
     * @param int $id
     * @return User|null
     */
    public static function getCachedUser($id)
    {
        $cacheKey = 'user:' . $id;

        return Cache::remember($cacheKey, now()->addHour(), function () use ($id, $cacheKey) {
            $user = static::find($id);
            if ($user) {
                $user->observe(new UserObserver($cacheKey));
            }
            return $user;
        });
    }

    //referral relationship using the 'referred_by' column
    public function referrer()
    {
        return $this->belongsTo(User::class, 'referred_by', 'username');
    }

    public function referredUsers()
    {
        return $this->hasMany(User::class, 'referred_by', 'username');
    }

    public function referrals()
    {
        return $this->referredUsers();
    }

    public function payments()
    {
        return $this->transactions();
    }


    public function getReferralTree($level = 1, $maxLevel = 10)
    {
        $tree = [];

        if ($level > $maxLevel) {
            return $tree;
        }

        $referrals = $this->referredUsers;

        foreach ($referrals as $referral) {
            $referralData = [
                'user' => $referral,
                'level' => $level,
                'children' => $referral->getReferralTree($level + 1, $maxLevel),
            ];

            $tree[] = $referralData;
        }

        return $tree;
    }


    // give referral bonus
    public function giveReferralBonus($depositAmount, $depth = 1)
    {
        if ($depth > 2 || !$this->referrer) {
            return;
        }

        // Calculate and award the bonus to the current upline member
        $percentage_bonus = json_decode(site('bonus'));
        $percentage_bonus = $percentage_bonus[$depth - 1];

        if ($percentage_bonus > 0) {
            $amount = $percentage_bonus / 100 * $depositAmount;
            $this->referrer->balance += $amount;
            // $this->referrer->balance += 5;
            $this->referrer->save();

            recordNewTransaction($amount, $this->referrer->id, 'credit', 'Referral Bonus', 'usd');

            // Recursively call the function for the next upline member
            $this->referrer->giveReferralBonus($depositAmount, $depth + 1);
        }
    }
    
    
    public function giveReferralBonusNGN($depositAmount, $depth = 1)
    {
        if ($depth > 2 || !$this->referrer) {
            return;
        }

        // Calculate and award the bonus to the current upline member
        $percentage_bonus = json_decode(site('bonus'));
        $percentage_bonus = $percentage_bonus[$depth - 1];

        if ($percentage_bonus > 0) {
            $amount = $percentage_bonus / 100 * $depositAmount;
            $this->referrer->ngn_balance += $amount;
            // $this->referrer->balance += 7750;
            $this->referrer->save();

            recordNewTransaction($amount, $this->referrer->id, 'credit', 'NGN Referral Bonus', 'ngn');

            // Recursively call the function for the next upline member
            $this->referrer->giveReferralBonusNGN($depositAmount, $depth + 1);
        }
    }
    
    
     /**
     * Get the plan associated with the user
     */
    public function plan()
    {
        return $this->belongsTo(Plan::class);
    }

    /**
     * Get the user's active mining plan
     */
    public function getActivePlan()
    {
        if ($this->plan_id) {
            return Plan::find($this->plan_id);
        }
        
        // Return default basic plan if no plan assigned
        return Plan::where('status', 'active')->orderBy('price', 'asc')->first();
    }
    
    
      /**
     * Check if user is a support agent (role >= 1)
     */
    public function isAgent()
    {
        return $this->role >= 1;
    }

    /**
     * Check if user is admin (role >= 2)
     */
    public function isAdmin()
    {
        return $this->role >= 2;
    }

    /**
     * Get support messages created by this user
     */
    public function supportMessages()
    {
        return $this->hasMany(SupportMessage::class);
    }

    /**
     * Get support messages assigned to this agent
     */
    public function assignedSupportMessages()
    {
        return $this->hasMany(SupportMessage::class, 'assigned_agent_id');
    }

    /**
     * Get support replies by this user
     */
    public function supportReplies()
    {
        return $this->hasMany(SupportReply::class);
    }

    /**
     * Get agents (users with role >= 1)
     */
    public static function agents()
    {
        return self::where('role', '>=', 1);
    }

    /**
     * Get active agents with their workload
     */
    public static function getAvailableAgents()
    {
        return self::where('role', '>=', 1)
            ->where('status', 'active')
            ->withCount(['assignedSupportMessages' => function($query) {
                $query->whereIn('status', [SupportMessage::STATUS_OPEN, SupportMessage::STATUS_PENDING]);
            }])
            ->orderBy('assigned_support_messages_count', 'asc')
            ->get();
    }

    /**
     * Get the balance deductions for the user.
     */
    public function balanceDeductions()
    {
        return $this->hasMany(UserBalanceDeduction::class);
    }
    
    
     /**
     * Get the bill payments for the user.
     */
    public function billPayments()
    {
        return $this->hasMany(BillPayment::class);
    }
    
    
        /**
     * Get the savings for the user.
     */
    public function savings()
    {
        return $this->hasMany(Savings::class);
    }

    /**
     * Get the active (running) savings for the user.
     */
    public function activeSavings()
    {
        return $this->hasMany(Savings::class)->where('status', 'running');
    }

    /**
     * Get the savings interest logs for the user.
     */
    public function savingsInterestLogs()
    {
        return $this->hasMany(SavingsInterestLog::class);
    }


    /**
     * Get the rent payments for the user.
     */
    public function rentPayments()
    {
        return $this->billPayments()->where('type', BillPayment::TYPE_RENT);
    }

    /**
     * Get the school fees payments for the user.
     */
    public function schoolFees()
    {
        return $this->billPayments()->where('type', BillPayment::TYPE_SCHOOL_FEES);
    }

    /**
     * Boot the model.
     */
    protected static function boot()
    {
        parent::boot();

        static::observe(UserObserver::class);
    }
}
