<?php

namespace App\Model\Client;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class wallet extends Model
{
    public $timestamps = false;
    protected $table = "wallet";
    protected $primaryKey = 'currency_code';

    public static function debitCharge($intCharge, $intClientId, $strCurrencyCode)
    {
        // Auto-update subscription status
        self::updateSubscriptionStatus($intClientId);

        return DB::connection('mysql_' . $intClientId)->table('wallet')->decrement('amount', $intCharge);
    }

    /**
     * Atomically debit wallet only if sufficient balance exists.
     * Uses WHERE amount >= charge to prevent race conditions.
     *
     * @return bool true if deducted, false if insufficient balance
     */
    public static function safeDebitCharge(float $charge, int $clientId, string $currencyCode): bool
    {
        self::updateSubscriptionStatus($clientId);

        $affected = DB::connection('mysql_' . $clientId)
            ->table('wallet')
            ->where('amount', '>=', $charge)
            ->update(['amount' => DB::raw("amount - {$charge}")]);

        if ($affected === 0) {
            \Illuminate\Support\Facades\Log::warning("Wallet debit rejected: insufficient balance", [
                'client_id' => $clientId,
                'charge'    => $charge,
                'currency'  => $currencyCode,
            ]);
            return false;
        }

        return true;
    }

    /**
     * Check if client has sufficient wallet balance.
     */
    public static function hasBalance(int $clientId, float $minimumRequired = 0.01): bool
    {
        $balance = (float) (DB::connection('mysql_' . $clientId)
            ->table('wallet')
            ->value('amount') ?? 0);

        return $balance >= $minimumRequired;
    }

    public static function creditCharge($intCharge, $intClientId, $strCurrencyCode)
    {
        // Auto-update subscription status
        self::updateSubscriptionStatus($intClientId);

        $conn = DB::connection('mysql_' . $intClientId)->table('wallet');

        // If wallet is empty → create with given currency + amount
        if ($conn->count() === 0) {
            $result = $conn->insert([
                'currency_code' => $strCurrencyCode,
                'amount' => $intCharge
            ]);
        } else {
            // Wallet exists → increment amount (no currency filter)
            $result = $conn->increment('amount', $intCharge);
        }

        // Auto-resume campaigns that were paused due to insufficient wallet balance
        self::resumeWalletPausedCampaigns($intClientId);

        return $result;
    }

    /**
     * Resume outbound_ai campaigns that were auto-paused due to insufficient wallet balance.
     * Only resumes if wallet balance is now > 0 AND pause_reason = 'insufficient_wallet'.
     * Campaigns paused manually (pause_reason IS NULL) or for other reasons are NOT touched.
     */
    public static function resumeWalletPausedCampaigns(int $clientId): int
    {
        $connection = DB::connection('mysql_' . $clientId);

        $balance = (float) ($connection->table('wallet')->value('amount') ?? 0);

        if ($balance <= 0) {
            return 0;
        }

        $resumed = $connection->table('campaign')
            ->where('dial_mode', 'outbound_ai')
            ->where('status', 0)
            ->where('pause_reason', 'insufficient_wallet')
            ->where('is_deleted', 0)
            ->update([
                'status'       => 1,
                'pause_reason' => null,
            ]);

        if ($resumed > 0) {
            \Illuminate\Support\Facades\Log::info(
                "Outbound campaigns auto-resumed after wallet recharge", [
                    'client_id'        => $clientId,
                    'campaigns_resumed' => $resumed,
                    'new_balance'      => $balance,
                ]
            );
        }

        return $resumed;
    }

    /**
     * Updates the local wallet's subscription status based on the master ClientPackage.
     * Uses Redis caching to avoid frequent DB queries.
     *
     * @param int $clientId
     * @return bool Is subscription active?
     */
    public static function updateSubscriptionStatus($clientId)
    {
        $redisKey = "subscription_check_recent:{$clientId}";
        $connectionName = 'mysql_' . $clientId;
        $isRecentlyChecked = null;

        // DEBUG: Log who called this function
        $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
        $callerInfo = collect($caller)->map(function ($frame) {
            return ($frame['class'] ?? '') . ($frame['type'] ?? '') . ($frame['function'] ?? '?') . ':' . ($frame['line'] ?? '?');
        })->implode(' <- ');
        \Illuminate\Support\Facades\Log::info("[SUBSCRIPTION_DEBUG] updateSubscriptionStatus called", [
            'client_id' => $clientId,
            'caller' => $callerInfo,
        ]);

        // Read current value BEFORE any changes
        $valueBefore = DB::connection($connectionName)->table('wallet')->value('is_subscription_active');
        \Illuminate\Support\Facades\Log::info("[SUBSCRIPTION_DEBUG] is_subscription_active BEFORE", [
            'client_id' => $clientId,
            'value' => $valueBefore,
        ]);

        try {
            $isRecentlyChecked = \Illuminate\Support\Facades\Redis::get($redisKey);
        } catch (\Exception $e) {
            // Redis unavailable - proceed to DB check
            \Illuminate\Support\Facades\Log::warning("Redis connection failed in updateSubscriptionStatus: " . $e->getMessage());
        }

        // 1. If recently checked, just return the current value from the local wallet table
        if ($isRecentlyChecked) {
            \Illuminate\Support\Facades\Log::info("[SUBSCRIPTION_DEBUG] Redis cache HIT - skipping DB check", [
                'client_id' => $clientId,
                'current_value' => $valueBefore,
            ]);
            return (bool) $valueBefore;
        }

        \Illuminate\Support\Facades\Log::info("[SUBSCRIPTION_DEBUG] Redis cache MISS - querying master DB", [
            'client_id' => $clientId,
        ]);

        // 2. If not cached, we need to check the Master DB
        try {
            $hasValidSubscription = \App\Model\Master\ClientPackage::where('client_id', $clientId)
                ->whereNotNull('razorpay_subscription_id')
                ->where('end_time', '>=', \Carbon\Carbon::now())
                ->exists();

            $isActive = $hasValidSubscription ? 1 : 0;

            \Illuminate\Support\Facades\Log::info("[SUBSCRIPTION_DEBUG] Master DB query result", [
                'client_id' => $clientId,
                'hasValidSubscription' => $hasValidSubscription,
                'isActive' => $isActive,
                'carbon_now' => \Carbon\Carbon::now()->toDateTimeString(),
            ]);

            // 3. Update local wallet table
            DB::connection($connectionName)
                ->table('wallet')
                ->update(['is_subscription_active' => $isActive]);

            // Read value AFTER update to confirm
            $valueAfter = DB::connection($connectionName)->table('wallet')->value('is_subscription_active');
            \Illuminate\Support\Facades\Log::info("[SUBSCRIPTION_DEBUG] is_subscription_active AFTER update", [
                'client_id' => $clientId,
                'value_before' => $valueBefore,
                'value_after' => $valueAfter,
                'intended' => $isActive,
            ]);

            // 4. Set cache to avoid re-checking for 60 minutes
            try {
                \Illuminate\Support\Facades\Redis::setex($redisKey, 3600, 1);
            } catch (\Exception $e) {
                \Illuminate\Support\Facades\Log::warning("[SUBSCRIPTION_DEBUG] Redis setex failed", [
                    'client_id' => $clientId,
                    'error' => $e->getMessage(),
                ]);
            }

            return $hasValidSubscription;

        } catch (\Throwable $e) {
            \Illuminate\Support\Facades\Log::error("[SUBSCRIPTION_DEBUG] Master DB query FAILED", [
                'client_id' => $clientId,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return (bool) DB::connection($connectionName)
                ->table('wallet')
                ->value('is_subscription_active');
        }
    }
}
