<?php

namespace App\Http\Controllers\Api\User;

use App\Http\Controllers\Controller;
use App\Models\Plan;
use App\Models\User;
use App\Models\MiningSession;
use App\Services\MiningService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use App\Models\Notification;

class MiningPlanApiController extends Controller
{
    protected $miningService;

    public function __construct(MiningService $miningService)
    {
        $this->miningService = $miningService;
    }

    /**
     * Get all available mining plans
     * @return JsonResponse
     */
    public function index(): JsonResponse
    {
        try {
            $user = Auth::user();
            $plans = Plan::where('status', 1)->orderBy('price', 'asc')->get();
            
            $userPlan = null;
            if ($user && $user->plan_id) {
                $userPlan = Plan::find($user->plan_id);
            }

            // Add calculated fields for each plan
            $enhancedPlans = $plans->map(function ($plan) use ($user) {
                $dailyReturn = ($plan->min_return_per_day + $plan->max_return_per_day) / 2;
                $dailyEarnings = $dailyReturn * $plan->miners;
                $hourlyEarnings = $dailyEarnings / 24;
                $roi = $plan->price > 0 ? (($dailyEarnings * 30) / $plan->price) * 100 : 0;
                
                // If user has no plan (plan_id is null), they get the free plan (ID 5)
                $userPlanId = $user ? ($user->plan_id ?? 5) : 5;
                
                return [
                    'id' => $plan->id,
                    'title' => $plan->title,
                    'price' => $plan->price,
                    'miners' => $plan->miners,
                    'speed' => $plan->speed,
                    'period' => $plan->period,
                    'min_return_per_day' => $plan->min_return_per_day,
                    'max_return_per_day' => $plan->max_return_per_day,
                    'maintenance_cost' => $plan->maintenance_cost,
                    'status' => $plan->status,
                    'daily_earnings' => round($dailyEarnings, 8),
                    'hourly_earnings' => round($hourlyEarnings, 8),
                    'roi_percentage' => round($roi, 2),
                    'is_user_plan' => $user && $user->plan_id == $plan->id,
                    'current_plan' => $userPlanId == $plan->id,
                    'can_purchase' => $user && $user->balance >= $plan->price,
                    'created_at' => $plan->created_at,
                    'updated_at' => $plan->updated_at
                ];
            });

            return response()->json([
                'status' => 'success',
                'message' => 'Mining plans retrieved successfully',
                'data' => [
                    'plans' => $enhancedPlans,
                    'user_plan' => $userPlan,
                    'user_balance' => $user ? $user->balance : 0,
                    'total_plans' => $plans->count()
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Failed to get mining plans', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to retrieve mining plans',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get specific plan details
     * @param int $id
     * @return JsonResponse
     */
    public function show($id): JsonResponse
    {
        try {
            $user = Auth::user();
            $plan = Plan::find($id);

            if (!$plan) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Plan not found'
                ], 404);
            }

            $dailyReturn = ($plan->min_return_per_day + $plan->max_return_per_day) / 2;
            $dailyEarnings = $dailyReturn * $plan->miners;
            $hourlyEarnings = $dailyEarnings / 24;
            $roi = $plan->price > 0 ? (($dailyEarnings * 30) / $plan->price) * 100 : 0;

            // If user has no plan (plan_id is null), they get the free plan (ID 5)
            $userPlanId = $user ? ($user->plan_id ?? 5) : 5;

            // Get plan statistics
            $stats = [
                'total_subscribers' => User::where('plan_id', $plan->id)->count(),
                'active_sessions' => MiningSession::where('plan_id', $plan->id)
                    ->where('is_active', true)
                    ->count(),
                'total_earnings_distributed' => MiningSession::where('plan_id', $plan->id)
                    ->sum('total_mined')
            ];

            $planData = [
                'id' => $plan->id,
                'title' => $plan->title,
                'price' => $plan->price,
                'miners' => $plan->miners,
                'speed' => $plan->speed,
                'period' => $plan->period,
                'min_return_per_day' => $plan->min_return_per_day,
                'max_return_per_day' => $plan->max_return_per_day,
                'maintenance_cost' => $plan->maintenance_cost,
                'status' => $plan->status,
                'daily_earnings' => round($dailyEarnings, 8),
                'hourly_earnings' => round($hourlyEarnings, 8),
                'roi_percentage' => round($roi, 2),
                'is_user_plan' => $user && $user->plan_id == $plan->id,
                'current_plan' => $userPlanId == $plan->id,
                'can_purchase' => $user && $user->balance >= $plan->price,
                'statistics' => $stats,
                'created_at' => $plan->created_at,
                'updated_at' => $plan->updated_at
            ];

            return response()->json([
                'status' => 'success',
                'message' => 'Plan details retrieved successfully',
                'data' => $planData
            ]);

        } catch (\Exception $e) {
            Log::error('Failed to get plan details', [
                'plan_id' => $id,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to retrieve plan details',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Purchase a mining plan
     * @param Request $request
     * @param int $id
     * @return JsonResponse
     */
    public function purchase(Request $request, $id): JsonResponse
    {
        try {
            $user = Auth::user();
            $plan = Plan::find($id);

            if (!$plan) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Plan not found'
                ], 404);
            }

            if ($plan->status != 1) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'This plan is not available for purchase'
                ], 400);
            }

            // Special handling for free plan (ID 5)
            if ($plan->id == 5) {
                // For free plan, just remove any existing plan assignment
                if ($user->plan_id && $user->plan_id != 5) {
                    // End any existing active sessions
                    $this->miningService->endUserActiveSessions($user);
                    
                    $user->plan_id = null;
                    $user->save();
                }
                
                return response()->json([
                    'status' => 'success',
                    'message' => 'Free plan activated successfully! You can now start mining.',
                    'data' => [
                        'plan' => [
                            'id' => $plan->id,
                            'title' => $plan->title,
                            'price' => $plan->price,
                            'period' => $plan->period,
                            'miners' => $plan->miners,
                            'speed' => $plan->speed
                        ],
                        'user' => [
                            'balance' => $user->balance,
                            'staked' => $user->staked,
                            'plan_id' => null // Free plan users have null plan_id
                        ],
                        'transaction_recorded' => false,
                        'can_start_mining' => true,
                        'is_free_plan' => true
                    ]
                ]);
            }

            if ($user->plan_id == $plan->id) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'You already have this plan active'
                ], 400);
            }

            if ($user->balance < $plan->price) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Insufficient balance. Please deposit funds first.',
                    'required_amount' => $plan->price,
                    'current_balance' => $user->balance,
                    'shortage' => $plan->price - $user->balance
                ], 400);
            }

            DB::beginTransaction();

            try {
                // End any existing active sessions
                $this->miningService->endUserActiveSessions($user);

                // Deduct plan cost from user balance
                $user->balance -= $plan->price;
                $user->staked += $plan->price;
                $user->plan_id = $plan->id;
                $user->save();

                // Record transaction
                recordNewTransaction($plan->price, $user->id, 'debit', 'Mining Plan Purchase: ' . $plan->title);

                DB::commit();

                Log::info('Mining plan purchased successfully', [
                    'user_id' => $user->id,
                    'plan_id' => $plan->id,
                    'plan_title' => $plan->title,
                    'cost' => $plan->price,
                    'remaining_balance' => $user->balance
                ]);
                
                $notification = new Notification();
            $notification->user_id = auth()->user()->id;
            $notification->title = "Mining Plan Purchase";
            $notification->message = "Mining Plan purchased successfully! You can now start mining!";
            $notification->status = 0;
            $notification->save();

                return response()->json([
                    'status' => 'success',
                    'message' => 'Plan purchased successfully! You can now start mining.',
                    'data' => [
                        'plan' => [
                            'id' => $plan->id,
                            'title' => $plan->title,
                            'price' => $plan->price,
                            'period' => $plan->period,
                            'miners' => $plan->miners,
                            'speed' => $plan->speed
                        ],
                        'user' => [
                            'balance' => $user->balance,
                            'staked' => $user->staked,
                            'plan_id' => $user->plan_id
                        ],
                        'transaction_recorded' => true,
                        'can_start_mining' => true
                    ]
                ]);

            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

        } catch (\Exception $e) {
            Log::error('Failed to purchase mining plan', [
                'user_id' => $user->id ?? null,
                'plan_id' => $id,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to purchase plan. Please try again.',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get user's current plan status
     * @return JsonResponse
     */
    public function userPlanStatus(): JsonResponse
    {
        try {
            $user = Auth::user();
            
            $plan = null;
            if ($user->plan_id) {
                $plan = Plan::find($user->plan_id);
                
                // Check if plan still exists and is active
                if (!$plan || $plan->status != 1) {
                    $user->plan_id = null;
                    $user->save();
                    $plan = null;
                }
            }
            
            // If no plan assigned, use free plan (ID 5)
            if (!$plan) {
                $plan = Plan::find(5);
                if (!$plan || $plan->status != 1) {
                    return response()->json([
                        'status' => 'error',
                        'message' => 'Free plan is not available. Please contact support.'
                    ], 500);
                }
            }

            $activeSession = $this->miningService->getUserActiveSession($user);

            $sessionData = null;
            if ($activeSession) {
                // Calculate current rewards
                $this->miningService->calculateMiningRewards($activeSession);
                $activeSession->refresh();

                $sessionData = [
                    'id' => $activeSession->id,
                    'started_at' => $activeSession->started_at->toISOString(),
                    'expires_at' => $activeSession->expires_at->toISOString(),
                    'total_mined' => $activeSession->total_mined,
                    'remaining_seconds' => $activeSession->getRemainingTimeInSeconds(),
                    'is_expired' => $activeSession->isExpired(),
                    'is_active' => $activeSession->is_active
                ];
            }

            return response()->json([
                'status' => 'success',
                'message' => 'User plan status retrieved',
                'data' => [
                    'has_plan' => true,
                    'plan' => [
                        'id' => $plan->id,
                        'title' => $plan->title,
                        'miners' => $plan->miners,
                        'speed' => $plan->speed,
                        'period' => $plan->period,
                        'min_return_per_day' => $plan->min_return_per_day,
                        'max_return_per_day' => $plan->max_return_per_day
                    ],
                    'active_session' => $sessionData,
                    'can_mine' => true,
                    'user_balance' => $user->coin_balance ?? 0,
                    'is_free_plan' => !$user->plan_id
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Failed to get user plan status', [
                'user_id' => Auth::id(),
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to retrieve plan status',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Cancel user's current plan
     * @return JsonResponse
     */
    public function cancelPlan(): JsonResponse
    {
        try {
            $user = Auth::user();

            if (!$user->plan_id) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'No active plan to cancel'
                ], 400);
            }

            $plan = Plan::find($user->plan_id);
            
            DB::beginTransaction();

            try {
                // End any active mining sessions
                $this->miningService->endUserActiveSessions($user);

                // Remove plan from user
                $user->plan_id = null;
                $user->save();

                DB::commit();

                Log::info('Mining plan cancelled', [
                    'user_id' => $user->id,
                    'plan_title' => $plan ? $plan->title : 'Unknown',
                    'cancelled_at' => now()
                ]);
                
                $notification = new Notification();
            $notification->user_id = auth()->user()->id;
            $notification->title = "Mining Plan Cancelled";
            $notification->message = "Mining Plan cancelled successfully!";
            $notification->status = 0;
            $notification->save();

                return response()->json([
                    'status' => 'success',
                    'message' => 'Plan cancelled successfully',
                    'data' => [
                        'plan_cancelled' => true,
                        'active_sessions_ended' => true,
                        'user_balance' => $user->coin_balance ?? 0
                    ]
                ]);

            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

        } catch (\Exception $e) {
            Log::error('Failed to cancel plan', [
                'user_id' => Auth::id(),
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to cancel plan',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get plan comparison data
     * @return JsonResponse
     */
    public function compare(): JsonResponse
    {
        try {
            $plans = Plan::where('status', 1)->orderBy('price', 'asc')->get();
            
            $comparison = $plans->map(function ($plan) {
                $dailyReturn = ($plan->min_return_per_day + $plan->max_return_per_day) / 2;
                $dailyEarnings = $dailyReturn * $plan->miners;
                $monthlyEarnings = $dailyEarnings * 30;
                $roi = $plan->price > 0 ? ($monthlyEarnings / $plan->price) * 100 : 0;
                $paybackDays = $plan->price > 0 ? $plan->price / $dailyEarnings : 0;

                return [
                    'id' => $plan->id,
                    'title' => $plan->title,
                    'price' => $plan->price,
                    'miners' => $plan->miners,
                    'speed' => $plan->speed,
                    'period' => $plan->period,
                    'daily_earnings' => round($dailyEarnings, 8),
                    'monthly_earnings' => round($monthlyEarnings, 8),
                    'roi_percentage' => round($roi, 2),
                    'payback_days' => round($paybackDays, 1),
                    'efficiency_score' => round($roi / max(1, $paybackDays) * 100, 2)
                ];
            });

            return response()->json([
                'status' => 'success',
                'message' => 'Plan comparison data retrieved',
                'data' => [
                    'plans' => $comparison,
                    'comparison_metrics' => [
                        'best_roi' => $comparison->max('roi_percentage'),
                        'fastest_payback' => $comparison->min('payback_days'),
                        'highest_daily_earnings' => $comparison->max('daily_earnings'),
                        'most_efficient' => $comparison->max('efficiency_score')
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Failed to get plan comparison', [
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to retrieve plan comparison',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get plan statistics
     * @return JsonResponse
     */
    public function statistics(): JsonResponse
    {
        try {
            $totalPlans = Plan::where('status', 1)->count();
            $totalUsers = User::whereNotNull('plan_id')->count();
            $activeSessions = MiningSession::where('is_active', true)->count();
            $totalEarnings = MiningSession::sum('total_mined');
            
            $planStats = Plan::where('status', 1)
                ->withCount(['users', 'miningSessions'])
                ->get()
                ->map(function ($plan) {
                    return [
                        'id' => $plan->id,
                        'title' => $plan->title,
                        'subscribers' => $plan->users_count,
                        'total_sessions' => $plan->mining_sessions_count,
                        'popularity_score' => $plan->users_count * 0.7 + $plan->mining_sessions_count * 0.3
                    ];
                })
                ->sortByDesc('popularity_score')
                ->values();

            return response()->json([
                'status' => 'success',
                'message' => 'Plan statistics retrieved',
                'data' => [
                    'overview' => [
                        'total_active_plans' => $totalPlans,
                        'total_subscribers' => $totalUsers,
                        'active_mining_sessions' => $activeSessions,
                        'total_earnings_distributed' => round($totalEarnings, 8)
                    ],
                    'plan_performance' => $planStats,
                    'most_popular_plan' => $planStats->first(),
                    'generated_at' => now()->toISOString()
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Failed to get plan statistics', [
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to retrieve statistics',
                'error' => $e->getMessage()
            ], 500);
        }
    }
}
