<?php

namespace App\Services;

use App\Models\Payment;
use App\Models\Pricing;
use App\Models\User;
use App\Models\UserPackage;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class PackageActivationService
{
    /**
     * Activate a package for a user based on a payment or direct assignment (alias).
     */
    public static function activatePackage($user, $package, ?int $paymentId = null, array $overrideData = []): UserPackage
    {
        return self::activatePackageForUser($user, $package, $paymentId, $overrideData);
    }

    /**
     * Activate a package for a user based on a payment or direct assignment.
     */
    public static function activatePackageForUser($user, $package, ?int $paymentId = null, array $overrideData = []): UserPackage
    {
        $userModel = is_object($user) ? $user : User::findOrFail($user);
        $packageModel = is_object($package) ? $package : Pricing::findOrFail($package);

        return DB::transaction(function () use ($userModel, $packageModel, $paymentId, $overrideData): UserPackage {
            $now = Carbon::now();

            // 1. Calculate expiration date based on validity length and type
            $validityLength = max(1, (int) ($packageModel->validity_length ?: 1));
            $validityType = strtolower((string) ($packageModel->validity_type ?: 'Day'));
            $billingType = $packageModel->billing_type ?: Pricing::BILLING_PER_SMS;

            $expireDate = null;
            if ($billingType === Pricing::BILLING_DAILY || $validityType === 'day' || $validityType === 'days') {
                $expireDate = $now->copy()->addDays($validityLength);
            } elseif ($billingType === Pricing::BILLING_MONTHLY || $validityType === 'month' || $validityType === 'months') {
                $expireDate = $now->copy()->addMonths($validityLength);
            } elseif ($billingType === Pricing::BILLING_YEARLY || $validityType === 'year' || $validityType === 'years') {
                $expireDate = $now->copy()->addYears($validityLength);
            } elseif ($validityType === 'week' || $validityType === 'weeks') {
                $expireDate = $now->copy()->addWeeks($validityLength);
            }

            if (isset($overrideData['expire_date']) && !empty($overrideData['expire_date'])) {
                $expireDate = Carbon::parse($overrideData['expire_date']);
            }

            // 2. Calculate SMS quota
            $totalSms = (int) ($packageModel->sms_limit ?: 0);
            if ($totalSms <= 0 && isset($overrideData['total_sms'])) {
                $totalSms = (int) $overrideData['total_sms'];
            }

            // If still 0 and payment amount is provided for per_sms package, calculate from rate
            if ($totalSms <= 0 && $paymentId) {
                $payment = Payment::find($paymentId);
                if ($payment && $payment->request_amount > 0) {
                    $rate = ($payment->sender_types == 1)
                        ? ($packageModel->masking_rate ?: $userModel->masking_rate ?: 0.50)
                        : ($packageModel->non_masking_rate ?: $userModel->non_masking_rate ?: 0.30);
                    if ($rate > 0) {
                        $totalSms = (int) floor($payment->request_amount / $rate);
                    }
                }
            }

            $dailyLimit = (int) ($packageModel->daily_limit ?: 0);
            if (isset($overrideData['daily_limit'])) {
                $dailyLimit = (int) $overrideData['daily_limit'];
            }

            $maskingRate = (float) ($packageModel->masking_rate ?: ($packageModel->type == 1 ? $packageModel->price : $userModel->masking_rate));
            $nonMaskingRate = (float) ($packageModel->non_masking_rate ?: ($packageModel->type != 1 ? $packageModel->price : $userModel->non_masking_rate));

            // 3. Mark previous active packages as replaced
            UserPackage::where('user_id', $userModel->id)
                ->where('status', UserPackage::STATUS_ACTIVE)
                ->update(['status' => UserPackage::STATUS_REPLACED]);

            // 4. Create new UserPackage record
            $userPackage = UserPackage::create([
                'user_id' => $userModel->id,
                'package_id' => $packageModel->id,
                'payment_id' => $paymentId,
                'package_name' => $packageModel->title,
                'billing_type' => $billingType,
                'price' => (float) $packageModel->price,
                'total_sms' => $totalSms,
                'used_sms' => 0,
                'daily_limit' => $dailyLimit,
                'daily_sent' => 0,
                'daily_sent_date' => $now->toDateString(),
                'masking_rate' => $maskingRate,
                'non_masking_rate' => $nonMaskingRate,
                'start_date' => $now,
                'expire_date' => $expireDate,
                'status' => UserPackage::STATUS_ACTIVE,
            ]);

            // 5. Update user rate and sender profile defaults
            $userModel->update([
                'masking_rate' => $maskingRate > 0 ? $maskingRate : $userModel->masking_rate,
                'non_masking_rate' => $nonMaskingRate > 0 ? $nonMaskingRate : $userModel->non_masking_rate,
            ]);

            Log::info("Package '{$packageModel->title}' activated for User #{$userModel->id} (UserPackage #{$userPackage->id}, Expiry: " . ($expireDate ? $expireDate->toDateTimeString() : 'Lifetime') . ")");

            return $userPackage;
        });
    }

    /**
     * Get active package for a user, handling automatic expiration and daily counters.
     */
    public static function getUserActivePackage($user): ?UserPackage
    {
        $userId = is_object($user) ? $user->id : (int) $user;

        $package = UserPackage::where('user_id', $userId)
            ->where('status', UserPackage::STATUS_ACTIVE)
            ->latest('id')
            ->first();

        if (!$package) {
            return null;
        }

        // Check if package expired by date or quota
        if ($package->is_expired) {
            $package->status = UserPackage::STATUS_INACTIVE;
            $package->save();
            return null;
        }

        // Check and reset daily sent if new date
        $package->checkAndResetDailySent();

        return $package;
    }

    /**
     * Check if user is eligible to send SMS based on their package and quota.
     *
     * @param User|int $user
     * @param int $smsCount
     * @param bool $isMasking
     * @return array{allowed: bool, reason: ?string, active_package: ?UserPackage, remaining_sms: int}
     */
    public static function canUserSendSms($user, int $smsCount = 1, bool $isMasking = false): array
    {
        $userModel = is_object($user) ? $user : User::find($user);
        if (!$userModel) {
            return [
                'allowed' => false,
                'reason' => 'User not found.',
                'active_package' => null,
                'remaining_sms' => 0,
            ];
        }

        if ($userModel->status === 0) {
            return [
                'allowed' => false,
                'reason' => 'User account is deactivated. Please contact support.',
                'active_package' => null,
                'remaining_sms' => 0,
            ];
        }

        $activePackage = self::getUserActivePackage($userModel);

        if ($activePackage) {
            // 1. Check expiration date
            if ($activePackage->expire_date && Carbon::now()->greaterThan($activePackage->expire_date)) {
                $activePackage->update(['status' => UserPackage::STATUS_INACTIVE]);
                return [
                    'allowed' => false,
                    'reason' => 'Your subscription package has expired. Please renew or purchase a package.',
                    'active_package' => null,
                    'remaining_sms' => 0,
                ];
            }

            // 2. Check total SMS quota limit
            if ($activePackage->total_sms > 0) {
                $remaining = max(0, $activePackage->total_sms - $activePackage->used_sms);
                if ($remaining < $smsCount) {
                    return [
                        'allowed' => false,
                        'reason' => "SMS quota exhausted. You have {$remaining} SMS remaining in your package.",
                        'active_package' => $activePackage,
                        'remaining_sms' => $remaining,
                    ];
                }
            }

            // 3. Check daily SMS limit
            if ($activePackage->daily_limit > 0) {
                $activePackage->checkAndResetDailySent();
                if (($activePackage->daily_sent + $smsCount) > $activePackage->daily_limit) {
                    $availableToday = max(0, $activePackage->daily_limit - $activePackage->daily_sent);
                    return [
                        'allowed' => false,
                        'reason' => "Daily SMS limit exceeded. You can send {$availableToday} more SMS today (Daily Limit: {$activePackage->daily_limit}).",
                        'active_package' => $activePackage,
                        'remaining_sms' => $activePackage->remaining_sms,
                    ];
                }
            }

            return [
                'allowed' => true,
                'reason' => null,
                'active_package' => $activePackage,
                'remaining_sms' => $activePackage->remaining_sms,
            ];
        }

        // Fallback: If no active package, check if user has standard balance or negative limit
        if (function_exists('balanceCheck')) {
            $rate = $isMasking ? ($userModel->masking_rate ?: 0.50) : ($userModel->non_masking_rate ?: 0.30);
            $chk = balanceCheck(1, $rate, $smsCount);
            if ($chk->crrAmount < 0 && !$chk->allowNegative) {
                return [
                    'allowed' => false,
                    'reason' => 'No active package and insufficient account balance. Please purchase an SMS package.',
                    'active_package' => null,
                    'remaining_sms' => 0,
                ];
            }
        }

        return [
            'allowed' => true,
            'reason' => null,
            'active_package' => null,
            'remaining_sms' => -1,
        ];
    }

    /**
     * Deduct SMS usage from active package.
     */
    public static function deductSmsUsage($user, int $smsCount = 1): void
    {
        $userId = is_object($user) ? $user->id : (int) $user;
        $activePackage = self::getUserActivePackage($userId);

        if ($activePackage) {
            $activePackage->checkAndResetDailySent();
            $activePackage->increment('used_sms', $smsCount);
            $activePackage->increment('daily_sent', $smsCount);

            if ($activePackage->total_sms > 0 && $activePackage->used_sms >= $activePackage->total_sms) {
                $activePackage->update(['status' => UserPackage::STATUS_INACTIVE]);
            }
        }
    }
}
