<?php

namespace App\Services;

use App\Models\MiningSession;
use App\Models\User;
use App\Models\UserCoinBalance;
use App\Models\Plan;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class MiningService
{
    public function startMiningSession(User $user, Plan $plan = null)
    {
        // End any existing active sessions for this user
        $this->endUserActiveSessions($user);

        // Cast period to integer and validate
        $periodHours = $plan ? (int) $plan->period : 1;
        $periodHours = max(1, min(8760, $periodHours)); // Between 1 hour and 1 year
        
        $expiresAt = Carbon::now()->addHours($periodHours);

        $session = MiningSession::create([
            'user_id' => $user->id,
            'plan_id' => $plan ? $plan->id : null,
            'started_at' => Carbon::now(),
            'expires_at' => $expiresAt,
            'total_mined' => 0,
            'last_calculated_at' => Carbon::now(),
            'is_active' => true
        ]);

        Log::info("Mining session started", [
            'user_id' => $user->id,
            'session_id' => $session->id,
            'plan' => $plan ? $plan->title : 'Free Plan',
            'period_hours' => $periodHours,
            'expires_at' => $expiresAt
        ]);

        return $session;
    }

    // public function calculateMiningRewards(MiningSession $session)
    // {
    //     if (!$session->is_active || $session->isExpired()) {
    //         return 0;
    //     }

    //     $plan = $session->plan;
    //     $user = $session->user;

    //     // Get plan parameters or default to free plan - cast numeric values
    //     $minReturn = $plan ? (float) $plan->min_return_per_day : 10.53500000;
    //     $maxReturn = $plan ? (float) $plan->max_return_per_day : 52.53500000;
    //     $maintenanceCost = $plan ? (float) $plan->maintenance_cost : 0;
    //     $miners = $plan ? (int) $plan->miners : 1;

    //     // Calculate time elapsed since last calculation
    //     $now = Carbon::now();
    //     $lastCalculated = $session->last_calculated_at;
    //     $minutesElapsed = $lastCalculated->diffInMinutes($now);

    //     if ($minutesElapsed < 1) {
    //         return 0; // Don't calculate for less than a minute
    //     }

    //     // Calculate earnings for the elapsed time
    //     $returnRange = $maxReturn - $minReturn;
    //     $dailyEarnings = $minReturn + ($returnRange * mt_rand() / mt_getrandmax());
        
    //     // Apply miners multiplier
    //     $dailyEarnings *= $miners;
        
    //     // Convert to per-minute rate
    //     $perMinuteEarnings = $dailyEarnings / (24 * 60);
        
    //     // Calculate total earnings for elapsed time
    //     $earnings = $perMinuteEarnings * $minutesElapsed;
        
    //     // Subtract maintenance cost
    //     $maintenancePerMinute = $maintenanceCost / (24 * 60);
    //     $earnings = max(0, $earnings - ($maintenancePerMinute * $minutesElapsed));

    //     // Update session and user balance in transaction
    //     DB::transaction(function () use ($session, $user, $earnings, $now) {
    //         $session->update([
    //             'total_mined' => $session->total_mined + $earnings,
    //             'last_calculated_at' => $now
    //         ]);

    //         $user->increment('coin_balance', $earnings);
            
    //         // log user coin_balance
    //     });

    //     Log::info("Mining rewards calculated", [
    //         'user_id' => $user->id,
    //         'session_id' => $session->id,
    //         'earnings' => $earnings,
    //         'minutes_elapsed' => $minutesElapsed
    //     ]);

    //     return $earnings;
    // }
    
    
    
   


public function calculateMiningRewards(MiningSession $session) 
{
    if (!$session->is_active || $session->isExpired()) {
        return 0;
    }

    $plan = $session->plan;
    $user = $session->user;

    // Get max return per day
    $maxReturn = $plan ? (float) $plan->max_return_per_day : 1.53500000;
    $maintenanceCost = $plan ? (float) $plan->maintenance_cost : 0;

    // Calculate time elapsed since last calculation
    $now = Carbon::now();
    $lastCalculated = $session->last_calculated_at ?? $session->started_at; // Add fallback for first calculation
    $minutesElapsed = $lastCalculated->diffInMinutes($now);

    // Add logging to debug the calculation
    \Log::info("Mining calculation debug", [
        'session_id' => $session->id,
        'user_id' => $user->id,
        'last_calculated' => $lastCalculated->toDateTimeString(),
        'now' => $now->toDateTimeString(),
        'minutes_elapsed' => $minutesElapsed,
        'current_total_mined' => $session->total_mined,
        'current_daily_earnings' => $session->daily_earnings,
        'max_return' => $maxReturn
    ]);

    // Only process if at least 5 minutes have elapsed (matching cron frequency)
    if ($minutesElapsed < 5) {
        \Log::info("Mining calculation skipped - insufficient time elapsed", [
            'session_id' => $session->id,
            'minutes_elapsed' => $minutesElapsed
        ]);
        return 0;
    }

    // Cap minutes to prevent massive calculations if cron missed runs
    if ($minutesElapsed > 60) {
        \Log::warning("Mining calculation capped - too many minutes elapsed", [
            'session_id' => $session->id,
            'original_minutes' => $minutesElapsed,
            'capped_to' => 60
        ]);
        $minutesElapsed = 60; // Cap at 1 hour max
    }

    // Reset daily earnings if it's a new day
    $todayStart = Carbon::today();
    if (!$session->daily_earnings_date || !Carbon::parse($session->daily_earnings_date)->isToday()) {
        \Log::info("Resetting daily earnings for new day", [
            'session_id' => $session->id,
            'old_daily_earnings' => $session->daily_earnings,
            'old_date' => $session->daily_earnings_date
        ]);
        $session->daily_earnings = 0;
        $session->daily_earnings_date = $todayStart;
    }
    
    // Check if already reached daily limit
    if ($session->daily_earnings >= $maxReturn) {
        \Log::info("Mining calculation skipped - daily limit reached", [
            'session_id' => $session->id,
            'daily_earnings' => $session->daily_earnings,
            'max_return' => $maxReturn
        ]);
        return 0;
    }

    // Fixed rate: always divide by 24 hours (1440 minutes)
    $earningsPerMinute = $maxReturn / 1440;
    $grossEarnings = ($earningsPerMinute * $minutesElapsed);
    
    // Subtract maintenance cost (also based on 24-hour rate)
    $maintenancePerMinute = $maintenanceCost / 1440;
    $netEarnings = max(0, $grossEarnings - ($maintenancePerMinute * $minutesElapsed));
    
    // Ensure we don't exceed daily limit
    $remainingEarnings = $maxReturn - $session->daily_earnings;
    $finalEarnings = min($netEarnings, $remainingEarnings);

    \Log::info("Mining calculation completed", [
        'session_id' => $session->id,
        'earnings_per_minute' => $earningsPerMinute,
        'minutes_elapsed' => $minutesElapsed,
        'gross_earnings' => $grossEarnings,
        'maintenance_cost' => ($maintenancePerMinute * $minutesElapsed),
        'net_earnings' => $netEarnings,
        'remaining_daily_limit' => $remainingEarnings,
        'final_earnings' => $finalEarnings
    ]);

    // Only update if there are actual earnings
    if ($finalEarnings > 0) {
        DB::transaction(function () use ($session, $user, $finalEarnings, $now, $todayStart) {
            // Update session
            $session->update([
                'total_mined' => $session->total_mined + $finalEarnings,
                'daily_earnings' => $session->daily_earnings + $finalEarnings,
                'daily_earnings_date' => $todayStart,
                'last_calculated_at' => $now
            ]);
            
            
            // add coin transaction
            $transaction = new UserCoinBalance();
            $transaction->user_id = $user->id;
            $transaction->miner_id = $session->id;
            $transaction->balance = $finalEarnings;
            $transaction->save();
            
            // Update user balance
            $user->coin_balance += $finalEarnings;
            $user->save();

            \Log::info("Mining rewards applied", [
                'session_id' => $session->id,
                'user_id' => $user->id,
                'earnings_added' => $finalEarnings,
                'new_total_mined' => $session->total_mined,
                'new_daily_earnings' => $session->daily_earnings,
                'new_user_balance' => $user->coin_balance
            ]);
        });
    } else {
        // Still update last_calculated_at even if no earnings
        $session->update(['last_calculated_at' => $now]);
    }

    return $finalEarnings;
}
    
//     public function calculateMiningRewards(MiningSession $session) 
// {
//     if (!$session->is_active || $session->isExpired()) {
//         return 0;
//     }

//     $plan = $session->plan;
//     $user = $session->user;

//     // Get plan parameters or default to free plan - cast numeric values
//     $minReturn = $plan ? (float) $plan->min_return_per_day : 0.53500000;
//     $maxReturn = $plan ? (float) $plan->max_return_per_day : 1.53500000;
//     $maintenanceCost = $plan ? (float) $plan->maintenance_cost : 0;
//     $miners = $plan ? (int) $plan->miners : 1;

//     // Calculate time elapsed since last calculation
//     $now = Carbon::now();
//     $lastCalculated = $session->last_calculated_at;
//     $minutesElapsed = $lastCalculated->diffInMinutes($now);

//     if ($minutesElapsed < 1) {
//         return 0; // Don't calculate for less than a minute
//     }

//     // Calculate earnings for the elapsed time
//     $returnRange = $maxReturn - $minReturn;
//     $dailyEarnings = $minReturn + ($returnRange * mt_rand() / mt_getrandmax());
    
//     // Apply miners multiplier
//     $dailyEarnings *= $miners;
    
//     // Convert to per-minute rate
//     $perMinuteEarnings = $dailyEarnings / (24 * 60);
    
//     // Calculate total earnings for elapsed time
//     $earnings = $perMinuteEarnings * $minutesElapsed;
    
//     // Subtract maintenance cost
//     $maintenancePerMinute = $maintenanceCost / (24 * 60);
//     $earnings = max(0, $earnings - ($maintenancePerMinute * $minutesElapsed));

//     DB::transaction(function () use ($session, $user, $earnings, $now) {
//         $session->update([
//             'total_mined' => $session->total_mined + $earnings,
//             'last_calculated_at' => $now
//         ]);
        
//         $user->coin_balance += $earnings;
//         $user->save();

//         // $user->increment('coin_balance', $earnings);
//     });

//     // Refresh user to get updated coin_balance
//     $user->refresh();

//     // Log detailed mining info
//     Log::info("Mining rewards calculated", [
//         'user_id' => $user->id,
//         'session_id' => $session->id,
//         'earnings' => $earnings,
//         'minutes_elapsed' => $minutesElapsed,
//         'coin_balance' => $user->coin_balance,
//         'total_mined' => $session->total_mined,
//         'calculated_at' => $now->toDateTimeString()
//     ]);

//     return $earnings;
// }

    

    public function processAllActiveSessions()
    {
        $activeSessions = MiningSession::where('is_active', true)
            ->where('expires_at', '>', Carbon::now())
            ->with(['user', 'plan'])
            ->get();

        $processedCount = 0;
        $totalEarnings = 0;

        foreach ($activeSessions as $session) {
            try {
                $earnings = $this->calculateMiningRewards($session);
                $totalEarnings += $earnings;
                $processedCount++;
            } catch (\Exception $e) {
                Log::error("Error processing mining session {$session->id}: " . $e->getMessage());
            }
        }

        // Clean up expired sessions
        $expiredCount = $this->cleanupExpiredSessions();

        Log::info("Mining processing completed", [
            'processed_sessions' => $processedCount,
            'expired_sessions' => $expiredCount,
            'total_earnings_distributed' => $totalEarnings
        ]);

        return [
            'processed' => $processedCount,
            'expired' => $expiredCount,
            'total_earnings' => $totalEarnings
        ];
    }

    public function cleanupExpiredSessions()
    {
        $expiredSessions = MiningSession::where('is_active', true)
            ->where('expires_at', '<=', Carbon::now())
            ->get();
            
        

        $expiredCount = 0;
        foreach ($expiredSessions as $session) {
            try {
                // Final calculation before ending session
                $this->calculateMiningRewards($session);
                
                // Mark as inactive
                $session->update(['is_active' => false]);
                $expiredCount++;
                
                $user = User::where('id',  $session->user_id)->first();
                $user->plan_id = null;
                $user->save();
                
                Log::info("Mining session expired", [
                    'session_id' => $session->id,
                    'user_id' => $session->user_id,
                    'total_mined' => $session->total_mined,
                    'user_plan' => $user->plan_id,
                ]);
            } catch (\Exception $e) {
                Log::error("Error expiring session {$session->id}: " . $e->getMessage());
            }
        }

        return $expiredCount;
    }

    public function endUserActiveSessions(User $user)
    {
        $activeSessions = MiningSession::where('user_id', $user->id)
            ->where('is_active', true)
            ->get();

        $endedCount = 0;
        foreach ($activeSessions as $session) {
            try {
                // Final calculation
                $this->calculateMiningRewards($session);
                
                // Mark as inactive
                $session->update(['is_active' => false]);
                $endedCount++;
                
                $user = User::where('id',  $session->user_id)->first();
                $user->plan_id = null;
                $user->save();
                
                Log::info("Mining session expired", [
                    'session_id' => $session->id,
                    'user_id' => $session->user_id,
                    'total_mined' => $session->total_mined,
                    'user_plan' => $user->plan_id,
                ]);
                
            } catch (\Exception $e) {
                Log::error("Error ending session {$session->id}: " . $e->getMessage());
            }
        }

        return $endedCount;
    }

    public function getUserActiveSession(User $user)
    {
        return MiningSession::where('user_id', $user->id)
            ->where('is_active', true)
            ->where('expires_at', '>', Carbon::now())
            ->with('plan')
            ->first();
    }
}