<?php

namespace App\Http\Controllers\Api\User;

use App\Http\Controllers\Controller;
use App\Jobs\ProcessAutoWithdrawJob;
use App\Models\AutoWallet;
use App\Models\DepositCoin;
use App\Models\User;
use App\Models\Withdrawal;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use OTPHP\TOTP;
use App\Models\Notification;

class WithdrawalApiController extends Controller
{
    private $baseUrlSafe = 'https://api.safehavenmfb.com';
    
    /**
     * Get all withdrawals for the authenticated user
     * 
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function index(Request $request)
    {
        try {
            $query = auth()->user()->withdrawals()->with('depositCoin');

            // Apply search filter if provided
            if ($request->has('search') && $request->search) {
                $query->where('ref', 'LIKE', '%' . $request->search . '%');
            }

            // Apply status filter if provided
            if ($request->has('status') && $request->status) {
                $query->where('status', $request->status);
            }

            // Apply date range filter if provided
            if ($request->has('from_date') && $request->from_date) {
                $query->whereDate('created_at', '>=', $request->from_date);
            }

            if ($request->has('to_date') && $request->to_date) {
                $query->whereDate('created_at', '<=', $request->to_date);
            }

            // Get all withdrawals without pagination
            $withdrawals = $query->orderBy('id', 'DESC')->get();

            // Get available withdrawal coins
            $coins = DepositCoin::where('can_withdraw', '1')->get(['id', 'name', 'code', 'logo_url', 'wallet_regex']);

            // Get user's auto wallets
            $auto_wallets = auth()->user()->autoWallets()->with('depositCoin:id,name,code')->get();

            // Format auto wallets array
            $auto_wallets_array = [];
            foreach ($auto_wallets as $wallet) {
                $auto_wallets_array[$wallet->depositCoin->code] = $wallet->wallet_address;
                
                // Auto-whitelist wallet if lock duration has passed
                if ($wallet->whitelisted == 0) {
                    $created_date = strtotime($wallet->created_at);
                    $to_be_whitelisted = (site('wallet_lock_duration') * 86400) + $created_date;
                    if ($to_be_whitelisted < time()) {
                        $wallet->update(['whitelisted' => 1]);
                    }
                }
            }

            // Get SafeHaven token and banks (optional - don't fail if this doesn't work)
            $banks = [];
            try {
                $token = $this->requestSafeHavenToken();
                
                if ($token) {
                    $response = $this->makeSafeHavenRequest('GET', '/transfers/banks', $token);
                    $responseBody = $response->json();
                    
                    if ($response->status() === 200 && 
                        isset($responseBody['responseCode']) && 
                        $responseBody['responseCode'] === '00') {
                        $banks = $responseBody['data'];
                    }
                }
            } catch (\Exception $e) {
                // Log the error but don't fail the entire request
                Log::warning('SafeHaven API request failed: ' . $e->getMessage());
                $banks = [];
            }

            // Calculate withdrawal statistics
            $stats = [
                'total_withdrawals' => auth()->user()->withdrawals()->count(),
                'pending_withdrawals' => auth()->user()->withdrawals()->where('status', 'pending')->count(),
                'approved_withdrawals' => auth()->user()->withdrawals()->where('status', 'approved')->count(),
                'rejected_withdrawals' => auth()->user()->withdrawals()->where('status', 'rejected')->count(),
                'total_amount_withdrawn' => auth()->user()->withdrawals()->where('status', 'approved')->sum('amount'),
                'pending_amount' => auth()->user()->withdrawals()->where('status', 'pending')->sum('amount'),
            ];

            return response()->json([
                'success' => true,
                'message' => 'Withdrawals retrieved successfully',
                'data' => [
                    'withdrawals' => $withdrawals,
                    'coins' => $coins,
                    'auto_wallets' => $auto_wallets,
                    'auto_wallets_array' => $auto_wallets_array,
                    'banks' => $banks,
                    'statistics' => $stats,
                    'withdrawal_settings' => [
                        'min_withdrawal' => site('min_withdrawal'),
                        'max_withdrawal' => site('max_withdrawal'),
                        'withdrawal_fee' => site('withdrawal_fee'),
                        'auto_withdraw' => site('auto_withdraw'),
                        'withdrawals_disabled' => site('dis_with') == 1,
                        'wallet_lock_duration' => site('wallet_lock_duration'),
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Withdrawal index error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve withdrawals',
                'error' => $e->getMessage()
            ], 500);
        }
    }
    
    
     private function requestSafeHavenToken()
    {
        $payload = [
            'grant_type' => 'client_credentials',
            'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
            'client_id' => '523d581921dd49665d3aae522b8baa02',
            'client_assertion' => 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jYnJpbGxpYW5jZS5pbyIsInN1YiI6IjUyM2Q1ODE5MjFkZDQ5NjY1ZDNhYWU1MjJiOGJhYTAyIiwiYXVkIjoiaHR0cHM6Ly9hcGkuc2FmZWhhdmVubWZiLmNvbSIsImlhdCI6MTc2MDU3NDA1OSwiZXhwIjoxODYwNTczOTQ2fQ.qWoBQ4kv7hpOqnH9fkop-AE3Sbjg3PO8CQKBmvITvxMGa-ULRK8ZD0vGMIpbUFd35dZgwwWsTyzuc14TIfJdZ448zqnymDOhTKTE3o9GtGpFCZ8ewB3Tp1ju9eGEnPfmBFmSxbFGb9GvzuBeAxZv08xfMatsqlyaD4dfoOr3Hyo' // Replace with actual JWT
        ];
    
        $response = $this->makeSafeHavenRequest('POST', '/oauth2/token', null, $payload);
        
        // return $response;
    
        return $response->successful()
            ? $response->json('access_token')
            : null;
    }


    private function makeSafeHavenRequest(string $method, string $endpoint, ?string $token = null, array $data = [])
    {
        $url = $this->baseUrlSafe . $endpoint;
    
        $headers = [
            'Accept' => 'application/json',
            'ClientID' => '523d581921dd49665d3aae522b8baa02',
        ];
    
        if ($token) {
            $headers['Authorization'] = 'Bearer ' . $token;
        }

        $http = Http::withHeaders($headers)
            ->timeout(30)
            ->withoutVerifying(); // Bypass SSL certificate verification        $method = strtoupper($method);
    
        switch ($method) {
            case 'POST':
                return $http->post($url, $data);
            case 'PUT':
                return $http->put($url, $data);
            case 'PATCH':
                return $http->patch($url, $data);
            case 'DELETE':
                return $http->delete($url, $data);
            default:
                return $http->get($url, $data);
        }
    }



    /**
     * Create a new withdrawal request
     * 
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function store(Request $request)
    {
        try {
            $request->validate([
                'amount' => 'required|numeric|min:0.01',
                'currency_code' => 'required|string',
                'wallet_address' => 'required|string'
            ]);
            
            
            // $totalDeposits = totalDeposits(auth()->user());
            
            $totalDeposits = 500;
        
            if (!$totalDeposits) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Your account is yet to reach the minimum capital of $300, kindly continue to grow your account or deposit to reach the threshold!'
                ], 422);
            }

            // Check if withdrawals are disabled
            if (site('dis_with') == 1) {
                return response()->json([
                    'success' => false,
                    'message' => 'Withdrawals are restricted at the moment, kindly contact admin!'
                ], 422);
            }

            $amount_before_fee = $request->amount;
            $currency = $request->currency_code;
            $fee = 2;
            $amount = $amount_before_fee - $fee;

            // Check min and max withdrawal limits
            if ($amount_before_fee < site('min_withdrawal') || $amount_before_fee > site('max_withdrawal')) {
                return response()->json([
                    'success' => false,
                    'message' => 'Min or max withdrawal amount not met',
                    'data' => [
                        'min_withdrawal' => site('min_withdrawal'),
                        'max_withdrawal' => site('max_withdrawal'),
                        'provided_amount' => $amount_before_fee
                    ]
                ], 422);
            }

            // Check for available balance
            if (auth()->user()->balance < $amount_before_fee) {
                return response()->json([
                    'success' => false,
                    'message' => 'Insufficient balance',
                    'data' => [
                        'current_balance' => auth()->user()->balance,
                        'required_amount' => $amount_before_fee
                    ]
                ], 422);
            }

            // Verify the coin exists and withdrawals are allowed
            $coin = DepositCoin::where('code', $currency)->where('can_withdraw', 1)->first();
            if (!$coin) {
                return response()->json([
                    'success' => false,
                    'message' => 'The payment method you have selected is not allowed for withdrawals'
                ], 422);
            }

            // Restrict withdrawal to coin that has been deposited by user
            $has_deposited_via_coin = auth()->user()->deposits()->where('deposit_coin_id', $coin->id)->first();
            if (!$has_deposited_via_coin) {
                return response()->json([
                    'success' => false,
                    'message' => 'You have not made deposit via ' . $coin->code . ' before'
                ], 422);
            }

            // Validate wallet address format
            $wallet_regex = $coin->wallet_regex;
            if (!preg_match('/' . $wallet_regex . '/', $request->wallet_address)) {
                return response()->json([
                    'success' => false,
                    'message' => 'The wallet address is not valid for the selected coin'
                ], 422);
            }

            $converted_amount = convertFiatToCrypto(site('currency'), $currency, $amount);
            $ref = uniqid('trx-');
            $type = 'manual'; // Default type

            // Handle auto withdrawal if enabled
            if (site('auto_withdraw') == 1) {
                $auto_wallet = auth()->user()->autoWallets()->where('wallet_address', $request->wallet_address)->first();
                if (!$auto_wallet) {
                    return response()->json([
                        'success' => false,
                        'message' => 'We could not verify the wallet address submitted'
                    ], 422);
                }

                if ($auto_wallet->depositCoin->code !== $currency) {
                    return response()->json([
                        'success' => false,
                        'message' => 'We could not verify the wallet address submitted'
                    ], 422);
                }

                // Check if wallet is whitelisted
                if ($auto_wallet->whitelisted == 0) {
                    return response()->json([
                        'success' => false,
                        'message' => 'The wallet you submitted is not whitelisted yet'
                    ], 422);
                }

                // Check NowPayments balance
                $api_key = env('NP_API_KEY');
                $response = Http::withHeaders([
                    'x-api-key' => $api_key,
                ])->get('https://api.nowpayments.io/v1/balance');

                if (!$response->successful()) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Error occurred while checking balance: ' . $response->status()
                    ], 422);
                }

                $balances = $response->json();
                $currency_lower = strtolower($currency);
                
                if (!array_key_exists($currency_lower, $balances)) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Error! Insufficient funds to cover withdrawal'
                    ], 422);
                }

                $balance = $balances[$currency_lower]['amount'];
                if ($converted_amount > $balance) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Error! Insufficient funds to cover withdrawal'
                    ], 422);
                }

                // Validate address with NowPayments
                $response = Http::withHeaders([
                    'x-api-key' => $api_key,
                    'Content-Type' => 'application/json',
                ])->post('https://api.nowpayments.io/v1/payout/validate-address', [
                    'address' => $request->wallet_address,
                    'currency' => $currency_lower,
                    'extra_id' => null,
                ]);

                if (!$response->successful()) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Error! Wallet Address not whitelisted'
                    ], 422);
                }

                // Dispatch auto withdrawal job
                ProcessAutoWithdrawJob::dispatch($request->wallet_address, $currency_lower, $converted_amount, $ref)
                    ->delay(now()->addMinutes(1));

                $type = 'auto';
            }

            // Debit user balance
            $user = User::find(auth()->user()->id);
            $user->balance = auth()->user()->balance - $amount_before_fee;
            $user->save();

            // Log transaction
            recordNewTransaction($amount_before_fee, auth()->user()->id, 'debit', 'New Withdrawal Request');

            // Store the withdrawal
            $withdrawal = new Withdrawal();
            $withdrawal->user_id = auth()->user()->id;
            $withdrawal->deposit_coin_id = $coin->id;
            $withdrawal->wallet_address = $request->wallet_address;
            $withdrawal->amount = $amount_before_fee;
            $withdrawal->converted_amount = $converted_amount;
            $withdrawal->fee = $fee;
            $withdrawal->status = 'pending';
            $withdrawal->type = $type;
            $withdrawal->ref = $ref;
            $withdrawal->save();

            // Send withdrawal notification email
            sendWithdrawalEmail($withdrawal);
            
            $notification = new Notification();
            $notification->user_id = auth()->user()->id;
            $notification->title = "Withdraw";
            $notification->message = "Withdrawal initiated successfully";
            $notification->status = 0;
            $notification->save();

            return response()->json([
                'success' => true,
                'message' => 'Withdrawal initiated successfully',
                'data' => [
                    'withdrawal' => [
                        'id' => $withdrawal->id,
                        'amount' => $amount_before_fee,
                        'fee' => $fee,
                        'net_amount' => $amount,
                        'currency' => $currency,
                        'converted_amount' => $converted_amount,
                        'ref' => $ref,
                        'wallet_address' => $request->wallet_address,
                        'status' => 'pending',
                        'type' => $type,
                        'created_at' => $withdrawal->created_at,
                    ]
                ]
            ], 201);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors()
            ], 422);
        } catch (\Exception $e) {
            Log::error('Withdrawal creation error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to create withdrawal',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Handle withdrawal callback from payment processor
     * 
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function withdrawalCallback(Request $request)
    {
        try {
            $ipn_secret = env('NP_SECRET_KEY');
            $error_msg = "Unknown error";
            $auth_ok = false;
            $request_data = null;

            // Verify HMAC signature
            if ($request->header('x-nowpayments-sig')) {
                $received_hmac = $request->header('x-nowpayments-sig');
                $request_json = $request->getContent();
                $request_data = json_decode($request_json, true);
                
                if ($request_data) {
                    ksort($request_data);
                    $sorted_request_json = json_encode($request_data);

                    if ($request_json !== false && !empty($request_json)) {
                        $hmac = hash_hmac("sha512", $sorted_request_json, $ipn_secret);

                        if ($hmac == $received_hmac) {
                            $auth_ok = true;
                        } else {
                            $error_msg = 'HMAC signature does not match';
                        }

                        // For development/testing purposes - remove in production
                        $auth_ok = true;
                    } else {
                        $error_msg = 'Error reading POST data';
                    }
                } else {
                    $error_msg = 'Invalid JSON data';
                }
            } else {
                $error_msg = 'No HMAC signature sent';
            }

            if (!$auth_ok || $request_data == null) {
                Log::error('Withdrawal callback authentication failed: ' . $error_msg);
                return response()->json([
                    'success' => false,
                    'message' => 'Authentication failed',
                    'error' => $error_msg
                ], 401);
            }

            // Process the callback
            $resp = json_decode($request->getContent());
            
            if (!$resp || !isset($resp->status) || !isset($resp->batch_withdrawal_id)) {
                Log::error('Invalid callback data structure');
                return response()->json([
                    'success' => false,
                    'message' => 'Invalid callback data structure'
                ], 400);
            }

            $status = strtolower($resp->status);
            $ref = 'trx-' . $resp->batch_withdrawal_id;

            // Find the withdrawal
            $withdrawal = Withdrawal::where('ref', $ref)->where('status', 'pending')->first();
            
            if (!$withdrawal) {
                Log::info('Withdrawal not found or already processed: ' . $ref);
                return response()->json([
                    'success' => false,
                    'message' => 'Withdrawal not found or already processed'
                ], 404);
            }

            // Process based on status
            if ($status == 'finished') {
                $withdrawal->update(['status' => 'approved']);
                
                // Send notification email
                sendWithdrawalEmail($withdrawal);
                
                // Send Telegram notification if function exists
                if (function_exists('sendMessageTelegram')) {
                    $message = "*Withdrawal Completed* \n" .
                             "⏰ Time: " . date('d-m-Y H:i:s') . " UTC\n" .
                             "💰 Currency: " . $resp->currency . "\n" .
                             "💵 Amount: " . formatAmount($withdrawal->amount) . "\n" .
                             "📤 Sent: " . $withdrawal->converted_amount . " " . $resp->currency . "\n" .
                             "📍 Address: " . $withdrawal->wallet_address . "\n" .
                             "🔗 Hash: " . ($resp->hash ?? 'N/A') . "\n" .
                             "💸 Fee: " . formatAmount($withdrawal->fee) . "\n" .
                             "✅ Status: Completed";
                    sendMessageTelegram($message);
                }
                
                Log::info('Withdrawal approved: ' . $ref);
                
                return response()->json([
                    'success' => true,
                    'message' => 'Withdrawal approved successfully',
                    'data' => [
                        'ref' => $ref,
                        'status' => 'approved',
                        'hash' => $resp->hash ?? null
                    ]
                ]);
                
            } elseif (in_array($status, ['failed', 'rejected'])) {
                $withdrawal->update(['status' => 'rejected']);

                // Refund the user
                $user = User::find($withdrawal->user_id);
                $new_balance = $user->balance + $withdrawal->amount;
                $user->update(['balance' => $new_balance]);
                
                // Record refund transaction
                recordNewTransaction($withdrawal->amount, $user->id, 'credit', 'Withdrawal reversal - ' . ucfirst($status));
                
                // Send notification email
                sendWithdrawalEmail($withdrawal);
                
                Log::info('Withdrawal rejected and refunded: ' . $ref);
                
                return response()->json([
                    'success' => true,
                    'message' => 'Withdrawal rejected and amount refunded',
                    'data' => [
                        'ref' => $ref,
                        'status' => 'rejected',
                        'refunded_amount' => $withdrawal->amount
                    ]
                ]);
            } else {
                Log::info('Unhandled withdrawal status: ' . $status . ' for ref: ' . $ref);
                return response()->json([
                    'success' => false,
                    'message' => 'Unhandled withdrawal status: ' . $status
                ], 400);
            }

        } catch (\Exception $e) {
            Log::error('Withdrawal callback error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Internal server error during callback processing',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get a specific withdrawal by ID
     * 
     * @param int $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function show($id)
    {
        try {
            $withdrawal = auth()->user()->withdrawals()
                ->with('depositCoin')
                ->where('id', $id)
                ->first();

            if (!$withdrawal) {
                return response()->json([
                    'success' => false,
                    'message' => 'Withdrawal not found'
                ], 404);
            }

            return response()->json([
                'success' => true,
                'message' => 'Withdrawal retrieved successfully',
                'data' => [
                    'withdrawal' => $withdrawal
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Withdrawal show error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve withdrawal',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get withdrawal methods and settings
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    public function methods()
    {
        try {
            $coins = DepositCoin::where('can_withdraw', '1')
                ->get(['id', 'name', 'code', 'logo_url', 'wallet_regex']);

            $auto_wallets = auth()->user()->autoWallets()
                ->with('depositCoin:id,name,code')
                ->get();

            return response()->json([
                'success' => true,
                'message' => 'Withdrawal methods retrieved successfully',
                'data' => [
                    'coins' => $coins,
                    'auto_wallets' => $auto_wallets,
                    'settings' => [
                        'min_withdrawal' => site('min_withdrawal'),
                        'max_withdrawal' => site('max_withdrawal'),
                        'withdrawal_fee' => site('withdrawal_fee'),
                        'auto_withdraw' => site('auto_withdraw'),
                        'withdrawals_disabled' => site('dis_with') == 1,
                        'wallet_lock_duration' => site('wallet_lock_duration'),
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Withdrawal methods error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve withdrawal methods',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get withdrawal statistics
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    public function statistics()
    {
        try {
            $user = auth()->user();
            
            $stats = [
                'total_withdrawals' => $user->withdrawals()->count(),
                'pending_withdrawals' => $user->withdrawals()->where('status', 'pending')->count(),
                'approved_withdrawals' => $user->withdrawals()->where('status', 'approved')->count(),
                'rejected_withdrawals' => $user->withdrawals()->where('status', 'rejected')->count(),
                'total_amount_withdrawn' => $user->withdrawals()->where('status', 'approved')->sum('amount'),
                'pending_amount' => $user->withdrawals()->where('status', 'pending')->sum('amount'),
                'total_fees_paid' => $user->withdrawals()->where('status', 'approved')->sum('fee'),
                'current_balance' => $user->balance,
                'this_month_withdrawals' => $user->withdrawals()
                    ->whereMonth('created_at', now()->month)
                    ->whereYear('created_at', now()->year)
                    ->count(),
                'this_month_amount' => $user->withdrawals()
                    ->where('status', 'approved')
                    ->whereMonth('created_at', now()->month)
                    ->whereYear('created_at', now()->year)
                    ->sum('amount'),
            ];

            return response()->json([
                'success' => true,
                'message' => 'Withdrawal statistics retrieved successfully',
                'data' => $stats
            ]);

        } catch (\Exception $e) {
            Log::error('Withdrawal statistics error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve withdrawal statistics',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Cancel a pending withdrawal
     * 
     * @param int $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function cancel($id)
    {
        try {
            $withdrawal = auth()->user()->withdrawals()
                ->where('id', $id)
                ->where('status', 'pending')
                ->first();

            if (!$withdrawal) {
                return response()->json([
                    'success' => false,
                    'message' => 'Pending withdrawal not found'
                ], 404);
            }

            // Only allow cancellation of manual withdrawals or auto withdrawals that haven't been processed
            if ($withdrawal->type === 'auto') {
                return response()->json([
                    'success' => false,
                    'message' => 'Auto withdrawals cannot be cancelled once initiated'
                ], 422);
            }

            // Update withdrawal status
            $withdrawal->update(['status' => 'cancelled']);

            // Refund the user
            $user = User::find(auth()->user()->id);
            $user->balance = $user->balance + $withdrawal->amount;
            $user->save();

            // Record refund transaction
            recordNewTransaction($withdrawal->amount, $user->id, 'credit', 'Withdrawal cancellation');

            return response()->json([
                'success' => true,
                'message' => 'Withdrawal cancelled successfully and amount refunded',
                'data' => [
                    'withdrawal_id' => $withdrawal->id,
                    'refunded_amount' => $withdrawal->amount,
                    'new_balance' => $user->balance
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Withdrawal cancellation error: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to cancel withdrawal',
                'error' => $e->getMessage()
            ], 500);
        }
    }
}
