<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class PayPalService
{
    private $clientId;
    private $clientSecret;
    private $sandbox;
    private $baseUrl;

    public function __construct()
    {
        $this->clientId = config_value('store_paypal_client_id', '');
        $this->clientSecret = config_value('store_paypal_client_secret', '');
        $this->sandbox = config_value('store_sandbox', true);
        $this->baseUrl = $this->sandbox 
            ? 'https://api-m.sandbox.paypal.com' 
            : 'https://api-m.paypal.com';
    }

    /**
     * Get cached access token or retrieve a new one (with debug logging)
     */
    public function getAccessToken()
    {
        if (empty($this->clientId) || empty($this->clientSecret)) {
            Log::error('PayPal credentials not configured');
            return null;
        }

        // Debug log the configuration
        Log::info('PayPal token request attempt', [
            'client_id' => substr($this->clientId, 0, 10) . '...',
            'sandbox' => $this->sandbox,
            'base_url' => $this->baseUrl
        ]);

        // Try to get cached token first
        $cacheKey = 'paypal_access_token_' . md5($this->clientId);
        $cachedToken = Cache::get($cacheKey);
        
        if ($cachedToken) {
            Log::info('Using cached PayPal token');
            return $cachedToken;
        }

        // Request new token
        Log::info('Requesting new PayPal token');
        
        $response = Http::asForm()
            ->withBasicAuth($this->clientId, $this->clientSecret)
            ->post($this->baseUrl . '/v1/oauth2/token', [
                'grant_type' => 'client_credentials'
            ]);

        // Debug log the response
        Log::info('PayPal token response', [
            'status' => $response->status(),
            'successful' => $response->successful(),
            'body_preview' => substr($response->body(), 0, 200)
        ]);

        if ($response->successful()) {
            $data = $response->json();
            $accessToken = $data['access_token'] ?? null;
            $expiresIn = $data['expires_in'] ?? 3600;
            
            if ($accessToken) {
                // Cache token for slightly less than expiry time
                Cache::put($cacheKey, $accessToken, now()->addSeconds($expiresIn - 60));
                Log::info('PayPal token cached successfully');
                return $accessToken;
            } else {
                Log::error('PayPal token response missing access_token', ['data' => $data]);
            }
        }

        Log::error('PayPal access token request failed', [
            'status' => $response->status(),
            'response' => $response->body(),
            'headers' => $response->headers()
        ]);
        
        return null;
    }

    /**
     * Create a PayPal order
     */
    public function createOrder($transaction, $itemName, $itemDescription = null)
    {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            throw new \Exception('Failed to get PayPal access token');
        }

        $orderData = [
            'intent' => 'CAPTURE',
            'purchase_units' => [[
                'reference_id' => (string) $transaction->id,
                'amount' => [
                    'currency_code' => config_value('store_currency', 'GBP'),
                    'value' => number_format($transaction->amount, 2, '.', '')
                ],
                'description' => $itemName,
                'custom_id' => $transaction->id,
            ]],
            'application_context' => [
                'brand_name' => config_value('site_name', 'EdgeRP'),
                'landing_page' => 'NO_PREFERENCE',
                'shipping_preference' => 'NO_SHIPPING',
                'user_action' => 'PAY_NOW',
                'return_url' => route('paypal.success', $transaction->id),
                'cancel_url' => route('payment.cancel', $transaction->id)
            ]
        ];

        $response = Http::withHeaders([
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $accessToken,
            'PayPal-Request-Id' => 'order-' . $transaction->id . '-' . time(), // Idempotency
        ])->post($this->baseUrl . '/v2/checkout/orders', $orderData);

        if ($response->successful()) {
            $orderResponse = $response->json();
            Log::info('PayPal order created successfully', [
                'transaction_id' => $transaction->id,
                'paypal_order_id' => $orderResponse['id'] ?? null
            ]);
            return $orderResponse;
        }

        Log::error('PayPal order creation failed', [
            'transaction_id' => $transaction->id,
            'status' => $response->status(),
            'response' => $response->body()
        ]);
        
        throw new \Exception('PayPal order creation failed: ' . $response->body());
    }

    /**
     * Capture a PayPal order
     */
    public function captureOrder($orderId)
    {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            throw new \Exception('Failed to get PayPal access token');
        }

        $response = Http::withHeaders([
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $accessToken,
        ])->post($this->baseUrl . "/v2/checkout/orders/{$orderId}/capture", (object)[]);

        if ($response->successful()) {
            $captureResponse = $response->json();
            Log::info('PayPal order captured successfully', [
                'paypal_order_id' => $orderId,
                'capture_id' => $captureResponse['id'] ?? null
            ]);
            return $captureResponse;
        }

        Log::error('PayPal order capture failed', [
            'paypal_order_id' => $orderId,
            'status' => $response->status(),
            'response' => $response->body()
        ]);
        
        throw new \Exception('PayPal order capture failed: ' . $response->body());
    }

    /**
     * Get order details
     */
    public function getOrderDetails($orderId)
    {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            throw new \Exception('Failed to get PayPal access token');
        }

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $accessToken,
        ])->get($this->baseUrl . "/v2/checkout/orders/{$orderId}");

        if ($response->successful()) {
            return $response->json();
        }

        Log::error('PayPal get order details failed', [
            'paypal_order_id' => $orderId,
            'status' => $response->status(),
            'response' => $response->body()
        ]);
        
        return null;
    }

    /**
     * Verify webhook signature (basic implementation)
     */
    public function verifyWebhookSignature($headers, $body)
    {
        // This is a simplified version
        // For production, you should implement proper webhook verification
        // See: https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature
        
        $webhookId = config_value('store_paypal_webhook_id', '');
        if (empty($webhookId)) {
            // If no webhook ID configured, skip verification (not recommended for production)
            Log::warning('PayPal webhook verification skipped - no webhook ID configured');
            return true;
        }

        // Basic header validation
        $requiredHeaders = ['PAYPAL-TRANSMISSION-ID', 'PAYPAL-CERT-ID', 'PAYPAL-TRANSMISSION-SIG'];
        foreach ($requiredHeaders as $header) {
            if (!isset($headers[strtolower($header)]) && !isset($headers[$header])) {
                Log::warning('PayPal webhook missing required header: ' . $header);
                return false;
            }
        }

        // For full implementation, you would:
        // 1. Get PayPal's certificate
        // 2. Verify the signature against the body
        // 3. Check timestamp validity
        // For now, we'll do basic validation and trust PayPal's network

        return true;
    }

    /**
     * Check if PayPal is properly configured
     */
    public function isConfigured()
    {
        return !empty($this->clientId) && !empty($this->clientSecret);
    }

    /**
     * Get PayPal SDK configuration for frontend
     */
    public function getSDKConfig()
    {
        return [
            'client_id' => $this->clientId,
            'currency' => config_value('store_currency', 'GBP'),
            'intent' => 'capture',
            'debug' => $this->sandbox,
            'sandbox' => $this->sandbox,
        ];
    }

    /**
     * Format amount for PayPal (ensures 2 decimal places)
     */
    public static function formatAmount($amount)
    {
        return number_format(floatval($amount), 2, '.', '');
    }

    /**
     * Get PayPal fees (approximate)
     * Note: Actual fees may vary by region and transaction type
     */
    public static function calculateFees($amount, $currency = 'GBP')
    {
        // These are approximate standard PayPal fees
        // You should check PayPal's current fee structure for accuracy
        $feeRates = [
            'GBP' => ['fixed' => 0.30, 'percentage' => 0.034],
            'USD' => ['fixed' => 0.30, 'percentage' => 0.029],
            'EUR' => ['fixed' => 0.35, 'percentage' => 0.034],
        ];

        $rates = $feeRates[$currency] ?? $feeRates['GBP'];
        $fee = ($amount * $rates['percentage']) + $rates['fixed'];
        
        return round($fee, 2);
    }
}