<?php
namespace BooklyPaypalPaymentsStandard\Lib\ProxyProviders;

use Bookly\Lib as BooklyLib;
use Bookly\Lib\Entities\CustomerAppointment;
use Bookly\Lib\Entities\Payment;
use Bookly\Lib\UserBookingData;
use Bookly\Lib\Utils\Common;
use BooklyPaypalPaymentsStandard\Lib;
use BooklyPro\Lib\Payment\PayPal;

/**
 * Class Shared
 * @package BooklyPaypalPaymentsStandard\Lib\ProxyProviders
 */
class Shared extends BooklyLib\Proxy\Shared
{
    /**
     * @inheritdoc
     */
    public static function getOutdatedUnpaidPayments( $payments )
    {
        $timeout = (int) get_option( 'bookly_paypal_timeout' );
        if ( $timeout ) {
            $rows = Payment::query( 'p' )
                ->select( 'p.id, p.details' )
                ->where( 'p.type', Payment::TYPE_PAYPAL )
                ->where( 'p.status', Payment::STATUS_PENDING )
                ->whereLt( 'p.created', date_create( current_time( 'mysql' ) )->modify( sprintf( '- %s seconds', $timeout ) )->format( 'Y-m-d H:i:s' ) )
                ->fetchArray();
            foreach ( $rows as $row ) {
                $payments[ $row['id'] ] = $row['details'];
            }
        }

        return $payments;
    }

    /**
     * @inheritdoc
     */
    public static function handleRequestAction( $action )
    {
        if ( get_option( 'bookly_paypal_enabled' ) === 'ps' ) {
            switch ( $action ) {
                case 'paypal-ps-return':
                    self::_success();
                    break;
                case 'paypal-ps-cancel':
                    self::_cancel();
                    break;
                case 'paypal-ps-ipn':
                    self::_ipn();
                    break;
            }
        }
    }

    /**
     * Process Payments Standard return request.
     */
    private static function _success()
    {
        $userData = new UserBookingData( self::parameter( 'bookly_fid' ) );
        $userData->load();
        $userData->setPaymentStatus( Payment::TYPE_PAYPAL, 'processing' );
        $userData->sessionSave();

        @wp_redirect( remove_query_arg( PayPal::$remove_parameters, Common::getCurrentPageURL() ) );
        exit;
    }

    /**
     * Process Payments Standard cancel request.
     */
    private static function _cancel()
    {
        $userData = new UserBookingData( self::parameter( 'bookly_fid' ) );
        $userData->load();
        $userData->setPaymentStatus( Payment::TYPE_PAYPAL, 'cancelled' );

        self::_cancelAppointment( $userData->getPaymentId() );
        $userData->sessionSave();

        @wp_redirect( remove_query_arg( PayPal::$remove_parameters, Common::getCurrentPageURL() ) );
        exit;
    }

    /**
     * Process Payments Standard IPN requests.
     */
    private static function _ipn()
    {
        if ( PayPal::verifyIPN() ) {
            $payment_id = (int) self::parameter( 'custom' );
            $payment    = new Payment();
            if ( $payment->loadBy( array( 'id' => $payment_id, 'type' => Payment::TYPE_PAYPAL ) ) ) {
                // Check if payment details match.
                switch ( false ) {
                    // Status
                    case ( $payment->getStatus() != Payment::STATUS_COMPLETED ):
                        // Currency
                    case ( self::parameter( 'mc_currency' ) == get_option( 'bookly_pmt_currency' ) ):
                        // PayPal ID
                    case (
                        self::parameter( 'receiver_email' ) == get_option( 'bookly_paypal_id' ) ||
                        self::parameter( 'receiver_id' ) == get_option( 'bookly_paypal_id' )
                    ):
                        // Amount
                    case ( abs( $payment->getPaid() - self::parameter( 'mc_gross' ) ) < 0.000001 ): // comparing 2 float numbers
                        // Something doesn't match.
                        break;
                    default:
                        // All matches.
                        switch ( self::parameter( 'payment_status' ) ) { // Grouped cases used
                            case 'Completed':
                                $payment->setStatus( Payment::STATUS_COMPLETED )->save();
                                if ( $order = BooklyLib\DataHolders\Booking\Order::createFromPayment( $payment ) ) {
                                    BooklyLib\Notifications\Cart\Sender::send( $order );
                                }
                                foreach (
                                    BooklyLib\Entities\Appointment::query( 'a' )
                                        ->leftJoin( 'CustomerAppointment', 'ca', 'a.id = ca.appointment_id' )
                                        ->where( 'ca.payment_id', $payment_id )->find() as $appointment
                                ) {
                                    BooklyLib\Proxy\Pro::syncGoogleCalendarEvent( $appointment );
                                    BooklyLib\Proxy\OutlookCalendar::syncEvent( $appointment );
                                }
                                break;
                            case 'Denied':
                            case 'Expired':
                            case 'Failed':
                            case 'Reversed':
                            case 'Voided':
                                // Cancel application
                                self::_cancelAppointment( $payment->getId() );
                                break;
                            case 'Canceled_Reversal':
                            case 'Created':
                            case 'Pending':
                            case 'Refunded':
                            case 'Processed':
                            default:
                                // Skip request
                                break;
                        }
                }

            }

        }
        exit;
    }


    /**
     * Cancel appointment and payment
     *
     * @param int $payment_id
     */
    private static function _cancelAppointment( $payment_id )
    {
        BooklyLib\Proxy\RecurringAppointments::cancelPayment( $payment_id );

        // Delete appointments.
        $ca_list = CustomerAppointment::query()
            ->where( 'payment_id', $payment_id )
            ->find();

        foreach ( $ca_list as $ca ) {
            /** @var CustomerAppointment $ca */
            $ca->deleteCascade();
        }

        // Delete payment.
        Payment::query()->delete()->where( 'id', $payment_id )->execute();
    }
}