<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use App\Model\Client\wallet;
use App\Model\Client\walletTransaction;
use Razorpay\Api\Api;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Cache;

class WalletController extends Controller
{
    function getWalletBalance(Request $request)
    {
        $response = DB::connection('mysql_' . $request->auth->parent_id)->select("SELECT amount FROM wallet");


        if (!$response) {
            return $this->successResponse("wallet data received successfully.", array("amount" => 0));
        } else {
            return $this->successResponse("wallet data received successfully.", (array) $response[0]);
        }
    }

    function getWalletCurrency(Request $request)
    {
        $response = DB::connection('mysql_' . $request->auth->parent_id)->select("SELECT currency_code, amount FROM wallet");

        if (!$response) {
            return $this->successResponse("wallet data received successfully.", array("currency_code" => 0, "amount" => 1));
        } else {
            return $this->successResponse("wallet data received successfully.", (array) $response[0]);
        }
    }

    function getWalletTransactions(Request $request)
    {
        $walletTransactions = DB::connection('mysql_' . $request->auth->parent_id)->select("SELECT * FROM wallet_transactions ORDER BY created_at DESC");

        if (count($walletTransactions) == 0) {
            return $this->successResponse("No Transactions found.", []);
        } else {
            return $this->successResponse("Transaction Retrieved successfully.", $walletTransactions);
        }
    }

    public function getWalletBalanceByClient(Request $request)
    {
        $this->validate($request, [
            'client_id' => 'required|integer',
        ]);

        $clientId = $request->input('client_id');
        $connectionName = 'mysql_' . $clientId;

        try {
            // Ensure connection exists in Lumen's config
            if (!array_key_exists($connectionName, config('database.connections'))) {
                return response()->json([
                    'status' => 'error',
                    'message' => "Database connection for client_id {$clientId} not found.",
                ], 404);
            }

            $result = DB::connection($connectionName)
                ->select("SELECT amount FROM wallet LIMIT 1");

            $amount = !empty($result) ? (float) $result[0]->amount : 0;

            return response()->json([
                'status' => 'success',
                'message' => 'Wallet balance fetched successfully.',
                'data' => [
                    'client_id' => $clientId,
                    'amount' => $amount,
                ],
            ], 200);
        } catch (\Throwable $e) {
            Log::error("Wallet balance fetch failed for client_id {$clientId}: " . $e->getMessage());

            return response()->json([
                'status' => 'error',
                'message' => 'Internal server error while fetching wallet balance.',
            ], 500);
        }
    }



    public function aiCallingDeductWalletBalance(Request $request)
    {
        $this->validate($request, [
            'client_id' => 'required|integer',
            'unique_id'    => 'required|string',
            'duration'  => 'required|integer|min:1',
        ]);

        $clientId = $request->input('client_id');
        $crdId = $request->input('unique_id');
        $duration = (int) $request->input('duration');

        try {
            // --- STEP 1: Get rate info ---
            $rateRow = DB::table('client_call_rates')
                ->where('client_id', $clientId)
                ->first();

            if (!$rateRow) {
                return response()->json([
                    'status'  => 'error',
                    'message' => "Rate not found for client_id {$clientId}.",
                ], 404);
            }

            $ratePerMinute = (float) $rateRow->rate;
            $currencyCode  = $rateRow->currency_code;

            // --- STEP 2: Convert seconds → minutes (round up) ---
            $minutes = ceil($duration / 60);

            // --- STEP 3: Calculate total charge ---
            $totalCharge = $minutes * $ratePerMinute;

            // --- STEP 4: Debit wallet (atomic, prevents negative balance) ---
            $debited = wallet::safeDebitCharge($totalCharge, $clientId, $currencyCode);
            if (!$debited) {
                // Balance insufficient — still debit via legacy method so the call
                // cost is recorded (call already happened), but log a warning.
                Log::warning("Wallet balance insufficient for safe debit, falling back to forced debit", [
                    'client_id' => $clientId,
                    'charge'    => $totalCharge,
                    'currency'  => $currencyCode,
                ]);
                wallet::debitCharge($totalCharge, $clientId, $currencyCode);
            }

            // --- STEP 5: Perform DB updates (CDR + ledger) ---
            DB::connection('mysql_' . $clientId)->transaction(function () use (
                $clientId,
                $currencyCode,
                $totalCharge,
                $crdId,
                $duration,
                $minutes,
                $ratePerMinute
            ) {
                // Record ledger entry
                $transaction = new walletTransaction();
                $transaction->setConnection("mysql_" . $clientId);
                $transaction->currency_code = $currencyCode;
                $transaction->amount = -$totalCharge;
                $transaction->transaction_type = 'debit';
                $transaction->transaction_reference = $crdId;
                $transaction->description = "Call charge for {$minutes} minute(s)";
                $transaction->created_at = Carbon::now();
                $transaction->saveOrFail();

                // Update CDR
                DB::connection("mysql_" . $clientId)
                    ->table('cdr_ai')
                    ->where('unique_id', $crdId)
                    ->update([
                        'duration'       => $duration,
                        'unit_minute'    => $minutes,
                        'charge'         => $ratePerMinute,
                        'billable_charge'=> $totalCharge,
                        'cost'           => $totalCharge,
                        'updated_at'     => Carbon::now(),
                    ]);
            });

            // --- STEP 6: Check for auto-recharge (INR clients only) ---
            $autoRechargeTriggered = false;
            if ($currencyCode === 'INR') {
                $this->triggerAutoRechargeIfNeeded($clientId);
            }

            // --- STEP 6.1: Check and send low balance email ---
            $this->sendLowBalanceEmailIfNeeded($clientId, $currencyCode);

            // --- STEP 7: Log success ---
            Log::info('Wallet debited and CDR updated', [
                'client_id' => $clientId,
                'unique_id'    => $crdId,
                'duration'  => $duration,
                'minutes'   => $minutes,
                'rate'      => $ratePerMinute,
                'charge'    => $totalCharge,
                'currency'  => $currencyCode,
            ]);

            // --- STEP 8: Return success response ---
            return response()->json([
                'status'  => 'success',
                'message' => 'Wallet debited first and CDR updated successfully.',
                'data'    => [
                    'client_id'        => $clientId,
                    'unique_id'           => $crdId,
                    'duration_seconds' => $duration,
                    'minutes_charged'  => $minutes,
                    'rate_per_minute'  => $ratePerMinute,
                    'deducted_amount'  => $totalCharge,
                    'currency'         => $currencyCode,
                ],
            ], 200);
        } catch (\Throwable $e) {
            Log::error('Wallet debit or CDR update failed', [
                'client_id' => $clientId,
                'error'     => $e->getMessage(),
            ]);

            return response()->json([
                'status'  => 'error',
                'message' => 'Operation failed: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * ----------------------------------------------------------------------------
     *  TRIGGER AUTO-RECHARGE IF WALLET BALANCE BELOW THRESHOLD
     * ----------------------------------------------------------------------------
     * Checks if the client's wallet balance is below their configured threshold
     * and triggers a Razorpay auto-recharge if they have a valid mandate.
     */
    private function triggerAutoRechargeIfNeeded($clientId)
    {
        try {
            // Get current wallet balance
            $walletBalance = (float) DB::connection('mysql_' . $clientId)
                ->table('wallet')
                ->value('amount') ?? 0;

            // Get owner user for this client
            $user = DB::connection('master')->table('users')
                ->where('parent_id', $clientId)
                ->first();

            if (!$user) {
                Log::warning("Auto-recharge: No owner found for client {$clientId}");
                return false;
            }

            // Check if auto-reload is enabled and mandate exists
            if ($user->auto_reload_enabled != 1 ||
                empty($user->razorpay_customer_id) ||
                empty($user->razorpay_token_id)) {
                return false;
            }

            $threshold = (float) ($user->auto_reload_threshold ?? 0);
            $rechargeAmount = (float) ($user->auto_reload_amount ?? 0);

            // Only trigger if balance is below threshold
            if ($walletBalance >= $threshold) {
                return false;
            }

            // ========== DUPLICATE PREVENTION ==========
            // Check if already pending or recently attempted
            $cooldownMinutes = 10;

            if ($user->auto_recharge_pending == 1) {
                Log::info("Auto-recharge: Already pending for client {$clientId}");
                return false;
            }

            if (!empty($user->auto_recharge_last_attempt)) {
                $lastAttempt = Carbon::parse($user->auto_recharge_last_attempt);
                $minutesSince = $lastAttempt->diffInMinutes(Carbon::now());

                if ($minutesSince < $cooldownMinutes) {
                    Log::info("Auto-recharge: Cooldown active for client {$clientId} ({$minutesSince} min since last attempt)");
                    return false;
                }
            }

            // Mark as pending before attempting
            DB::connection('master')->table('users')
                ->where('id', $user->id)
                ->update([
                    'auto_recharge_pending' => 1,
                    'auto_recharge_last_attempt' => Carbon::now()
                ]);

            // ========== TRIGGER RAZORPAY RECHARGE (RECURRING PAYMENT) ==========
            $rzpKey = env('RAZORPAY_KEY');
            $rzpSecret = env('RAZORPAY_SECRET');

            if (empty($rzpKey) || empty($rzpSecret)) {
                Log::error("Auto-recharge: Razorpay credentials not configured");
                $this->clearAutoRechargePending($user->id);
                return false;
            }

            $api = new Api($rzpKey, $rzpSecret);
            $amountPaise = intval($rechargeAmount * 100);

            // 1. Create Order
            $order = $api->order->create([
                'amount'   => $amountPaise,
                'currency' => 'INR',
                'receipt'  => 'auto_recharge_' . time(),
                'notes'    => [
                    'type'      => 'auto_recharge',
                    'client_id' => $clientId,
                    'user_id'   => $user->id
                ]
            ]);

            Log::info('Auto-recharge: Order created', ['order_id' => $order['id']]);

            // 2. Create Recurring Payment
            $payment = $api->payment->createRecurring([
                'email'       => $user->email,
                'contact'     => $user->mobile,
                'amount'      => $amountPaise,
                'currency'    => 'INR',
                'order_id'    => $order['id'],
                'customer_id' => $user->razorpay_customer_id,
                'token'       => $user->razorpay_token_id,
                'description' => 'Wallet Auto-Recharge',
                'notes'       => [
                    'type'      => 'auto_recharge',
                    'client_id' => $clientId,
                    'user_id'   => $user->id
                ]
            ]);

            Log::info('Auto-recharge triggered via Recurring Payment', [
                'client_id'       => $clientId,
                'wallet_balance'  => $walletBalance,
                'recharge_amount' => $rechargeAmount,
                'payment_id'      => $payment['razorpay_payment_id'],
                'order_id'        => $order['id']
            ]);

            return true;

        } catch (\Throwable $e) {
            Log::error('Auto-recharge trigger failed', [
                'client_id' => $clientId,
                'error' => $e->getMessage()
            ]);

            // Clear pending flag on failure
            if (isset($user->id)) {
                $this->clearAutoRechargePending($user->id);
            }

            return false;
        }
    }

    /**
     * Clear auto-recharge pending flag for a user
     */
    private function clearAutoRechargePending($userId)
    {
        DB::connection('master')->table('users')
            ->where('id', $userId)
            ->update(['auto_recharge_pending' => 0]);
    }

    /**
     * ----------------------------------------------------------------------------
     *  CHECK CLIENT ELIGIBILITY (Subscription + Wallet Balance)
     * ----------------------------------------------------------------------------
     * Returns whether the client is allowed to make AI calls.
     * 
     * POST /client/check-eligibility
     * Payload: { "client_id": 123 }
     * 
     * Response:
     * - { "allow": true }
     * - { "allow": false, "reason": "LOW_BALANCE" }
     * - { "allow": false, "reason": "SUBSCRIPTION_EXPIRED" }
     * - { "allow": false, "reason": "NO_SUBSCRIPTION" }
     */
    public function checkClientEligibility(Request $request)
    {
        // Validate X-CLIENT header
        $clientKey = $request->header('X-CLIENT');
        if ($clientKey !== env('X_CLIENT')) {
            return response()->json(['allow' => false, 'reason' => 'UNAUTHORIZED'], 401);
        }

        $this->validate($request, [
            'client_id' => 'required|integer',
        ]);

        $clientId = $request->input('client_id');

        try {
            // --- STEP 1: Get client info ---
            $client = DB::connection('master')
                ->table('clients')
                ->where('id', $clientId)
                ->first();

            if (!$client) {
                return response()->json([
                    'allow'  => false,
                    'reason' => 'CLIENT_NOT_FOUND',
                ], 404);
            }

            $currencyCode = $client->currency_code ?? 'USD';

            // --- STEP 2: Check subscription (INR clients only) ---
            if ($currencyCode === 'INR') {
                // Sync subscription status first
                \App\Model\Client\wallet::updateSubscriptionStatus($clientId);

                $hasValidSubscription = \App\Model\Master\ClientPackage::where('client_id', $clientId)
                    ->whereNotNull('razorpay_subscription_id')
                    ->where('end_time', '>=', Carbon::now())
                    ->exists();

                if (!$hasValidSubscription) {
                    // Check if they ever had a subscription
                    $hadSubscription = \App\Model\Master\ClientPackage::where('client_id', $clientId)
                        ->whereNotNull('razorpay_subscription_id')
                        ->exists();

                    return response()->json([
                        'allow'  => false,
                        'reason' => $hadSubscription ? 'SUBSCRIPTION_EXPIRED' : 'NO_SUBSCRIPTION',
                    ], 200);
                }
            }

            // --- STEP 3: Check wallet balance ---
            $connectionName = 'mysql_' . $clientId;

            if (!array_key_exists($connectionName, config('database.connections'))) {
                return response()->json([
                    'allow'  => false,
                    'reason' => 'DATABASE_NOT_FOUND',
                ], 404);
            }

            $walletBalance = (float) (DB::connection($connectionName)->table('wallet')->value('amount') ?? 0);

            // Minimum balance threshold (can be configurable)
            $minimumBalance = 1;

            if ($walletBalance < $minimumBalance) {
                // --- STEP 3a: Trigger auto-recharge for INR clients if enabled ---
                $autoRechargeTriggered = false;
                if ($currencyCode === 'INR') {
                    $autoRechargeTriggered = $this->triggerAutoRechargeIfNeeded($clientId);
                }

                return response()->json([
                    'allow'   => false,
                    'reason'  => 'LOW_BALANCE',
                    'balance' => $walletBalance,
                    'auto_recharge_triggered' => $autoRechargeTriggered,
                ], 200);
            }

            // --- STEP 4: All checks passed ---
            return response()->json([
                'allow'   => true,
                'balance' => $walletBalance,
            ], 200);

        } catch (\Throwable $e) {
            Log::error('Client eligibility check failed', [
                'client_id' => $clientId,
                'error'     => $e->getMessage(),
            ]);

            return response()->json([
                'allow'  => false,
                'reason' => 'INTERNAL_ERROR',
            ], 500);
        }
    }

    /**
     * ----------------------------------------------------------------------------
     *  SEND LOW BALANCE EMAIL
     * ----------------------------------------------------------------------------
     * Sends an email to admin if the wallet balance is 0 or less.
     * Uses Redis to throttle emails (1 per hour per client).
     */
    private function sendLowBalanceEmailIfNeeded($clientId, $currencyCode)
    {
        try {
            // 1. Get current wallet balance
            $walletBalance = (float) DB::connection('mysql_' . $clientId)
                ->table('wallet')
                ->value('amount') ?? 0;

            // 2. Check if balance is low (<= 0)
            // You can adjust this threshold (e.g., <= 5)
            if ($walletBalance > 0) {
                return;
            }

            // 3. Check throttle (1 hour cooldown)
            $cacheKey = "low_balance_email_sent:{$clientId}";
            
            if (Cache::has($cacheKey)) {
                return;
            }

            // 4. Send Email
            $adminEmail = env('ADMIN_NOTIFY_EMAIL');

            if (empty($adminEmail)) {
                Log::warning("Low Balance: ADMIN_NOTIFY_EMAIL not set");
                return;
            }

            $subject = "⚠️ Low Wallet Balance Alert - Client {$clientId}";
            
            $currentDate = \Carbon\Carbon::now()->format('d M Y, h:i A');
            $adminBodyContent = "
                <div style='background: #dc3545; color: white; padding: 12px; border-radius: 5px; margin-bottom: 20px;'>
                    <h2 style='margin: 0;'>⚠️ Low Wallet Balance Alert</h2>
                </div>
                <p style='color: #555;'>The wallet balance for <strong>Client {$clientId}</strong> has dropped below zero. Please take necessary action.</p>
                <table cellpadding='8' cellspacing='0' width='100%' style='margin-top: 20px; border-collapse: collapse; border: 1px solid #ddd;'>
                    <tr style='background: #f8f8f8;'>
                        <td colspan='2' style='border-bottom: 1px solid #ddd; padding: 10px;'><strong style='color: #333; font-size: 16px;'>Wallet Details</strong></td>
                    </tr>
                    <tr>
                        <td style='background: #f2f2f2; width:150px; border-bottom: 1px solid #ddd;'><strong>Client ID</strong></td>
                        <td style='border-bottom: 1px solid #ddd;'>{$clientId}</td>
                    </tr>
                    <tr>
                        <td style='background: #f2f2f2; border-bottom: 1px solid #ddd;'><strong>Current Balance</strong></td>
                        <td style='border-bottom: 1px solid #ddd; color: #dc3545; font-weight: bold;'>{$walletBalance} {$currencyCode}</td>
                    </tr>
                    <tr>
                        <td style='background: #f2f2f2; border-bottom: 1px solid #ddd;'><strong>Timestamp</strong></td>
                        <td style='border-bottom: 1px solid #ddd;'>{$currentDate}</td>
                    </tr>
                </table>
                <p style='margin-top: 25px; color: #555;'>This is an automated system alert.</p>
            ";

            // Use the standard Razorpay notification view wrapper if available, otherwise fallback to sending raw HTML
            try {
                $emailHtml = view('emails.razorpay.notification', [
                    'subject' => $subject,
                    'body' => $adminBodyContent
                ])->render();
            } catch (\Throwable $e) {
                // Fallback if view doesn't exist or fails (though we verified it exists)
                $emailHtml = $adminBodyContent;
            }

            $result = send_sendgrid_mail($adminEmail, $subject, $emailHtml);

            if ($result['success']) {
                Log::info("Low balance email sent for client {$clientId}");
                // 5. Set Cache throttle (1 hour = 3600 seconds)
                // Laravel 10 Cache::put takes $seconds as 3rd arg for int
                Cache::put($cacheKey, true, 3600);
            } else {
                Log::error("Failed to send low balance email for client {$clientId}: {$result['error']}");
            }

        } catch (\Throwable $e) {
            Log::error("Error in sendLowBalanceEmailIfNeeded for client {$clientId}: " . $e->getMessage());
        }
    }
}
