<?php

namespace App\Http\Controllers\Frontend\TopUp\Traits;

use Illuminate\Support\Facades\RateLimiter;
use GuzzleHttp\Exception\ClientException;

trait RateLimitingTrait
{
    /**
     * Check rate limiting for payment requests.
     * 
     * @param int $userId User ID for rate limiting key
     * @param string $gateway Payment gateway name (e.g., 'pakasir', 'tripay', 'duitku')
     * @param int $maxAttempts Maximum attempts allowed (default: 3)
     * @param int $decayMinutes Decay time in minutes (default: 1)
     * @return array ['allowed' => bool, 'error' => string|null, 'seconds' => int|null]
     */
    protected function checkPaymentRateLimit(
        int $userId, 
        string $gateway, 
        int $maxAttempts = 3, 
        int $decayMinutes = 1
    ): array {
        $rateLimitKey = $gateway . '_payment_' . $userId;
        
        if (RateLimiter::tooManyAttempts($rateLimitKey, $maxAttempts)) {
            $seconds = RateLimiter::availableIn($rateLimitKey);
            return [
                'allowed' => false,
                'error' => 'Too many payment requests. Please wait ' . $seconds . ' seconds before trying again.',
                'seconds' => $seconds,
            ];
        }
        
        RateLimiter::hit($rateLimitKey, $decayMinutes * 60);
        
        return [
            'allowed' => true,
            'error' => null,
            'seconds' => null,
        ];
    }

    /**
     * Handle payment API exceptions with user-friendly messages.
     * 
     * @param \Exception $e The exception to handle
     * @param string $gateway Payment gateway name for logging
     * @return array ['error' => string, 'status_code' => int|null]
     */
    protected function handlePaymentException(\Exception $e, string $gateway): array
    {
        // Handle Guzzle HTTP client exceptions (429, 4xx, 5xx errors)
        if ($e instanceof ClientException) {
            $statusCode = $e->getResponse()->getStatusCode();
            
            \Log::error($gateway . ' payment client exception', [
                'status_code' => $statusCode,
                'error' => $e->getMessage(),
            ]);
            
            if ($statusCode === 429) {
                return [
                    'error' => 'Too many requests to payment server. Please wait a moment before trying again.',
                    'status_code' => $statusCode,
                ];
            }
            
            if ($statusCode >= 400 && $statusCode < 500) {
                return [
                    'error' => 'Invalid payment request. Please check your details and try again.',
                    'status_code' => $statusCode,
                ];
            }
            
            return [
                'error' => 'An error occurred while processing your payment. Please try again later.',
                'status_code' => $statusCode,
            ];
        }

        // Handle server-side exceptions (5xx errors from GuzzleHttp)
        if ($e instanceof \GuzzleHttp\Exception\ServerException) {
            $statusCode = $e->getResponse()->getStatusCode();
            
            \Log::error($gateway . ' payment server exception', [
                'status_code' => $statusCode,
                'error' => $e->getMessage(),
            ]);
            
            return [
                'error' => 'Payment server is temporarily unavailable. Please try again later.',
                'status_code' => $statusCode,
            ];
        }

        // Handle connection exceptions (timeouts, network issues)
        if ($e instanceof \GuzzleHttp\Exception\ConnectException) {
            \Log::error($gateway . ' payment connection exception', [
                'error' => $e->getMessage(),
            ]);
            
            return [
                'error' => 'Unable to connect to payment server. Please check your connection and try again.',
                'status_code' => null,
            ];
        }

        // Handle general exceptions
        \Log::error($gateway . ' payment exception', [
            'error' => $e->getMessage(),
            'class' => get_class($e),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'trace' => $e->getTraceAsString(),
        ]);
        
        return [
            'error' => 'A payment error occurred. Please try again later.',
            'status_code' => null,
        ];
    }

    /**
     * Get user-friendly error message for HTTP status codes.
     * 
     * @param int $statusCode HTTP status code
     * @return string User-friendly error message
     */
    protected function getHttpErrorMessage(int $statusCode): string
    {
        return match(true) {
            $statusCode === 429 => 'Too many requests to payment server. Please wait a moment before trying again.',
            $statusCode === 401 => 'Payment authentication failed. Please contact support.',
            $statusCode === 403 => 'Payment request was denied. Please contact support.',
            $statusCode === 404 => 'Payment service not found. Please try again later.',
            $statusCode >= 400 && $statusCode < 500 => 'Invalid payment request. Please check your details and try again.',
            $statusCode >= 500 => 'Payment server is temporarily unavailable. Please try again later.',
            default => 'An unexpected error occurred. Please try again.',
        };
    }
}
