<?php

namespace App\Http\Controllers\Front;

use App\Payment;
use App\User;
use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Omnipay\Omnipay;
use Paymentwall_Pingback;

class DonateController extends Controller
{
    protected $gateway;

    public function __construct()
    {
        $this->middleware( 'auth', ['except' => ['getPaymentwall', 'postPaypalWebhook']] );

        $this->gateway = Omnipay::create( 'PayPal_Rest' );
        $this->gateway->initialize([
            'clientId' => settings( 'paypal_client_id' ),
            'secret'   => settings( 'paypal_secret' ),
            'testMode' => false,
        ]);
    }

    public function getIndex()
    {
        pagetitle( [ trans( 'main.apps.donate' ), settings( 'server_name' ) ] );
        return view( 'front.donate.index' );
    }

    public function postPaypalSubmit( Request $request )
    {
        $user = Auth::user();
        
        $transaction = $this->gateway->purchase([
            'amount'        => number_format( $request->dollars, 2 ),
            'currency'      => settings( 'paypal_currency' ),
            'description'   => trans( 'donate.paypal.description', [ 'amount' => $request->dollars, 'currency' => settings( 'currency_name' ) ] ),
            'returnUrl'     => url( 'donate/paypal/complete' ),
            'cancelUrl'     => url( 'donate' ),
            'custom'        => json_encode([
                'user_id' => $user->ID,
                'timestamp' => time()
            ])
        ]);
        $response = $transaction->send();

        if ( $response->isRedirect() )
        {
            $response->redirect();
        }
        else
        {
            echo $response->getMessage();
        }
    }

    public function postPaypalComplete( Request $request )
    {
        $complete = $this->gateway->completePurchase([
            'transactionReference' => $request->paymentId,
            'payerId' => $request->PayerID,
        ]);

        $response = $complete->send();
        $data = $response->getData();

        if ( $data['state'] === 'approved' )
        {
            $user = Auth::user();
            $amount = round( $data['transactions'][0]['amount']['total'] );

            $payment_amount = settings( 'paypal_double' ) ? ( $amount * settings( 'paypal_per' ) ) * 2 : $amount * settings( 'paypal_per' );

            Payment::create([
                'user_id' => $user->ID,
                'transaction_id' => $data['id'],
                'amount' => $payment_amount
            ]);

            $user->money = $user->money + $payment_amount;
            $user->save();

        }

        flash()->success( trans( 'donate.paypal.success' ) );
        return redirect( 'donate' );
    }

    /**
     * Handle PayPal webhook notifications (replaces old IPN system)
     * This endpoint should be configured in your PayPal app webhook settings
     */
    public function postPaypalWebhook( Request $request )
    {
        try {
            // Get the webhook payload
            $payload = $request->getContent();
            $headers = $request->headers->all();
            
            // Verify webhook signature (recommended for production)
            if (!$this->verifyPaypalWebhook($payload, $headers)) {
                Log::warning('PayPal webhook signature verification failed');
                return response('Webhook signature verification failed', 400);
            }

            $event = json_decode($payload, true);
            
            if (!$event || !isset($event['event_type'])) {
                Log::warning('Invalid PayPal webhook payload');
                return response('Invalid payload', 400);
            }

            Log::info('PayPal webhook received', ['event_type' => $event['event_type']]);

            // Handle different webhook events
            switch ($event['event_type']) {
                case 'PAYMENT.SALE.COMPLETED':
                    $this->handlePaymentCompleted($event);
                    break;
                    
                case 'PAYMENT.SALE.DENIED':
                case 'PAYMENT.SALE.REFUNDED':
                    $this->handlePaymentRefunded($event);
                    break;
                    
                default:
                    Log::info('Unhandled PayPal webhook event', ['event_type' => $event['event_type']]);
            }

            return response('OK', 200);
            
        } catch (\Exception $e) {
            Log::error('PayPal webhook processing error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return response('Internal server error', 500);
        }
    }

    /**
     * Verify PayPal webhook signature
     */
    private function verifyPaypalWebhook($payload, $headers)
    {
        // For production, implement proper webhook signature verification
        // This is a simplified version - you should use PayPal's SDK for proper verification
        
        $webhookId = settings('paypal_webhook_id'); // You'll need to add this setting
        
        if (empty($webhookId)) {
            // If no webhook ID is configured, skip verification (not recommended for production)
            return true;
        }

        // In a real implementation, you would:
        // 1. Get the cert ID from headers
        // 2. Download the cert from PayPal
        // 3. Verify the signature using the cert
        // For now, we'll just return true but log the attempt
        
        Log::info('PayPal webhook signature verification attempted', [
            'webhook_id' => $webhookId,
            'headers' => array_keys($headers)
        ]);
        
        return true;
    }

    /**
     * Handle completed payment webhook
     */
    private function handlePaymentCompleted($event)
    {
        $resource = $event['resource'];
        $transactionId = $resource['id'];
        $amount = floatval($resource['amount']['total']);
        
        // Check if we already processed this transaction
        $existingPayment = Payment::where('transaction_id', $transactionId)->first();
        if ($existingPayment) {
            Log::info('PayPal payment already processed', ['transaction_id' => $transactionId]);
            return;
        }

        // Extract custom data to identify the user
        $customData = isset($resource['custom']) ? json_decode($resource['custom'], true) : null;
        
        if (!$customData || !isset($customData['user_id'])) {
            Log::warning('PayPal payment missing user identification', ['transaction_id' => $transactionId]);
            return;
        }

        $user = User::find($customData['user_id']);
        if (!$user) {
            Log::warning('PayPal payment for non-existent user', [
                'transaction_id' => $transactionId,
                'user_id' => $customData['user_id']
            ]);
            return;
        }

        // Calculate payment amount based on settings
        $payment_amount = settings('paypal_double') ? 
            ($amount * settings('paypal_per')) * 2 : 
            $amount * settings('paypal_per');

        // Create payment record
        Payment::create([
            'user_id' => $user->ID,
            'transaction_id' => $transactionId,
            'amount' => $payment_amount
        ]);

        // Add money to user account
        $user->money = $user->money + $payment_amount;
        $user->save();

        Log::info('PayPal payment processed successfully', [
            'transaction_id' => $transactionId,
            'user_id' => $user->ID,
            'amount' => $payment_amount
        ]);
    }

    /**
     * Handle refunded payment webhook
     */
    private function handlePaymentRefunded($event)
    {
        $resource = $event['resource'];
        $transactionId = $resource['parent_payment'];
        
        $payment = Payment::where('transaction_id', $transactionId)->first();
        if (!$payment) {
            Log::warning('PayPal refund for unknown payment', ['transaction_id' => $transactionId]);
            return;
        }

        $user = User::find($payment->user_id);
        if ($user) {
            // Remove the money from user account
            $user->money = max(0, $user->money - $payment->amount);
            $user->save();
        }

        // Mark payment as refunded or delete it
        $payment->delete();

        Log::info('PayPal refund processed', [
            'transaction_id' => $transactionId,
            'user_id' => $payment->user_id,
            'amount' => $payment->amount
        ]);
    }

    /**
     * Process the PaymentWall payment
     *
     * @param Request $request
     */
    public function getPaymentWall( Request $request )
    {
        $pingback = new Paymentwall_Pingback( $_GET, $_SERVER['REMOTE_ADDR'] );
        if ( $pingback->validate() )
        {
            $virtualCurrency = $pingback->getVirtualCurrencyAmount();
            $user = User::find( $request->uid );

            if ( settings( 'paymentwall_double' ) )
            {
                $n_credits = $virtualCurrency * 2;
            }
            else
            {
                $n_credits = $virtualCurrency;
            }

            if ( $pingback->isDeliverable() )
            {
                // Give credits to user
                $user->money = $user->money + $n_credits;
                $user->save();

                Payment::create([
                    'user_id' => $user->ID,
                    'transaction_id' => $request->ref,
                    'amount' => $n_credits
                ]);
            }
            elseif ( $pingback->isCancelable() )
            {
                // Remove credits from user
                $user->money = $user->money + $n_credits;
                $user->save();

                $payment = Payment::find( $request->ref );
                $payment->delete();
            }
            echo 'OK'; // Paymentwall expects response to be OK, otherwise the pingback will be resent
        }
        else
        {
            echo $pingback->getErrorSummary();
        }
    }
}
