<?php

namespace WPAdverts\Stripe;

class Gateway {
    
    /**
     * Class constructor
     * 
     * @since 1.0
     * @return void
     */
    public function __construct() {
        
        // enqueue scripts and styles
        add_filter("adverts_action_payment", array( $this, "init" ) );
        add_filter("shortcode_atts_shortcode_payments_complete", array( $this, "init" ) );
        add_filter("wpadverts_filter_renewals", array( $this, "init" ) );
        
        add_action("adext_register_payment_gateway", array( $this, "register" ) );
        add_filter("adverts_form_bind", array( $this, "bind" ), 10, 2 );
        //add_action("init", array( $this, "init" ) );
    }
    
    /**
     * Enqueues WPAdverts Stripe Styles and Scripts
     * 
     * This function enqueues WPAdverts Stripe scripts and styles in 
     * [adverts_add] third step.
     * 
     * The function is called by adverts_action_payment filter.
     * 
     * @since 1.0.0
     * 
     * @see  adverts_action_payment filter
     * 
     * @param   string $html
     * @return  string
     */
    public function init( $html ) {
        wp_enqueue_script( 'wpadverts-stripe-main' );
        wp_enqueue_style( 'wpadverts-stripe-main' );
        return $html;
    }
    
    /**
     * Registers new payment method
     * 
     * This function is called by adext_register_payment_gateway action and
     * registers a new payment method
     * 
     * @since 1.0.0
     * 
     * @see adext_register_payment_gateway action
     * 
     * @return void
     */
    public function register() {
        $title = __("Stripe", "wpadverts-stripe");

        if( adverts_config( "stripe.custom_title" ) ) {
            $title = adverts_config( "stripe.custom_title" );
        }

        adverts_form_add_field("adverts_stripe_html", array(
            "renderer" => array( $this, "html_element" ),
            "callback_save" => null,
            "callback_bind" => null,
        ));
        
        $payment_form = array(
            "name" => "adverts-stripe",
            "action" => "",
            "field" => array(
                array(
                    "name" => "_stripe_token",
                    "type" => "adverts_field_hidden",
                    "order" => 0
                ),
                array(
                    "name" => "adverts_person",
                    "type" => "adverts_field_text",
                    "order" => 10,
                    "label" => __( "Contact Person", "wpadverts-stripe" ),
                    "is_required" => true,
                    "validator" => array( 
                        array( "name" => "is_required" ),
                    )
                ),
                array(
                    "name" => "adverts_email",
                    "type" => "adverts_field_text",
                    "order" => 10,
                    "label" => __( "Email", "wpadverts-stripe" ),
                    "is_required" => true,
                    "validator" => array( 
                        array( "name" => "is_required" ),
                        array( "name" => "is_email" )
                    )
                ),
                
            )
        ); // end payment-form
        
        if( ! is_admin() || adverts_request( "page" ) != 'adext-payment-history' ) {
            $payment_form["field"][] = array(
                "name" => "credit_card",
                "type" => "adverts_stripe_html",
                "order" => 10,
                "label" => __( "Payment Information", "wpadverts-stripe" ),
                "is_required" => true,
                "validator" => array( 
                )
            );
        }
        
        adext_payment_gateway_add("stripe", array(
            "name" => "stripe",
            "title" => $title,
            "order" => 10,
            "data" => array(),
            "callback" => array(
                "render" => array( $this, "render" )
            ),
            "form" => array(
                "payment_form" => $payment_form
            ) // end form
        ));
    }
    
    /**
     * Handles the Stripe payment
     * 
     * This function is executed when user tries to make a Stripe payment
     * from [adverts_add] third step.
     * 
     * @param   array $data   Payment data
     * @return  array         Response which will be print on screen
     */
    public function render( $data ) {
        try {
            $bind = $data["bind"];
        
            if( $bind["_stripe_save_card"] ) {
                update_post_meta( $data['payment_id'], "_wpadverts_stripe_save_cc", "pending" );
            }

            return array(
                "result" => 1,
                "html" => "",
                "execute" => null, // null|click|submit
                "execute_id" => ""
            );
            

        } catch (\Exception $e) {
            
            header("HTTP/1.0 500 Internal Server Error");
            
            wp_update_post(array("ID"=>$data['payment_id'], "post_status"=>"failed"));

            do_action("adverts_payment_failed", get_post( $data['payment_id'] ) );
            
            adext_payments_log($data['payment_id'], __( "Payment failed.", "wpadverts-stripe" ) );
            adext_payments_log($data['payment_id'], sprintf( __( "Stripe: %s.", "wpadverts-stripe" ), $e->getMessage() ) );
            
            $result = array(
                "result" => 0,
                "html" => $e->getMessage(),
                "execute" => null, // null|click|submit
                "execute_id" => ""
            );
        }
        
        return $result;
    }
    
    /**
     * Converts the price to cents
     * 
     * The price passed to stripe should be cents, so for example if the price 
     * is $10.00 then the value sent to price should be 1000.
     * 
     * @since  1.1.0
     * @param  float  $price    A price with floating point number
     * @return int              The amount in cents
     */
    public function amount_to_int( $price ) {
        return $price*pow( 10, adverts_config( 'config.currency_decimals' ) );
    }

    /**
     * Generates a success message for successful payment.
     * 
     * This function is executed when a successful payment was made.
     * 
     * @since   1.0
     * 
     * @param   array     $data       Payment data
     * @param   object    $charge     Charge object
     * @return  string                The success message
     */
    public function get_success_message( $data, $charge ) {
        $object_id = get_post_meta( $data['payment_id'], "_adverts_object_id", true );
        $advert = get_post( $object_id );
        
        if( $advert->post_status == "publish" ) {
            $m = __( 'Your Ad has been published. You can see it <a href="%s">here</a>.', "wpadverts-stripe" );
            $m = sprintf( $m, get_permalink( $advert->ID ) );
        } else {
            $m = __( 'Your Ad is pending. It will be published once an Administrator will approve it.', 'wpadverts-stripe' );
        }
        
        $response = '<div class="wpadverts-stripe-payment-success">';
        $response.= '<div><span class="wpadverts-stripe-payment-success-icon adverts-icon-ok"></span></div>';
        $response.= '<div class="wpadverts-stripe-payment-success-text"><p>' . $m . '</p></div>';
        $response.= '</div>';
        
        return $response;
    }

    /**
     * Displays a credit card field in [adverts_add]
     * 
     * This function renders the credit card field in [adverts_add] third step.
     * 
     * @since 1.0
     * @param array $field
     * @return void
     */
    public function html_element( $field ) {
        
        try {
        
            $stripe_customer = get_user_meta( get_current_user_id(), Core::get_customer_meta_key_name(), true );
            $stripe_default_card = "";
            $cards = array();

            $icons = array(
                "American Express" => 'adverts-icon-cc-amex',
                "Diners Club" => 'adverts-icon-cc-diners-club',
                "Discover" => 'adverts-icon-cc-discover',
                "JCB" => 'adverts-icon-cc-jcb',
                "MasterCard" => 'adverts-icon-cc-mastercard',
                "UnionPay" => 'adverts-icon-credit-card',
                "Visa" => 'adverts-icon-cc-visa',
                "Unknown" => 'adverts-icon-credit-card',
                
                "American Express" => 'adverts-icon-cc-amex',
                "Diners Club" => 'adverts-icon-cc-diners-club',
                "discover" => 'adverts-icon-cc-discover',
                "jcb" => 'adverts-icon-cc-jcb',
                "mastercard" => 'adverts-icon-cc-mastercard',
                "unionpay" => 'adverts-icon-credit-card',
                "visa" => 'adverts-icon-cc-visa',
                "unknown" => 'adverts-icon-credit-card'
            );

            if( ! class_exists( "\Stripe\Stripe" ) ) {
                include_once Core::get_instance()->get_basedir() . '/stripe/init.php';
            }
            
            \Stripe\Stripe::setApiKey( adverts_config( 'stripe.secret_key' ) );
            
            if( get_current_user_id() && $stripe_customer ) {
                $cards = \Stripe\PaymentMethod::all(["customer" => $stripe_customer, "type" => "card"]);
                $customer = \Stripe\Customer::retrieve($stripe_customer);

                if( isset( $customer->invoice_settings->default_payment_method ) && ! empty( $customer->invoice_settings->default_payment_method ) ) {
                    $stripe_default_card = $customer->invoice_settings->default_payment_method;
                } else if( $customer->default_source ) {
                    $stripe_default_card = $customer->default_source;
                }
            }

            if( adverts_request( "payment_id" ) ) {
                $payment_id = absint( adverts_request( "payment_id" ) );
            } else if( adverts_request( "advert-hash" ) ) {
                $payment_id = adverts_get_post_id_from_hash( adverts_request( "advert-hash" ) );
            }
            
            $intent = $this->_get_payment_intent( $payment_id, "object" );
            
            include Core::get_instance()->get_basedir() . '/includes/credit-card-field.php';
        } catch(\Exception $e) {
            echo $e->getMessage();
        }
    }
    
    /**
     * Retruns Payment Intent (id or object)
     * 
     * The function returns existing PaymentIntent or if the PaymentIntent does
     * not exist creates a new one.
     * 
     * @since   1.1.0
     * @param   int       $payment_id       Payment ID
     * @param   string    $return           Data to return; one of: 'id' or 'all' 
     * @return  mixed                       Either Payment Intent object or id
     */
    protected function _get_payment_intent( $payment_id, $return = "id" ) {
        
        $payment_intent_id = get_post_meta( $payment_id, '_adverts_payment_intent_id', true );
        
        if( $payment_intent_id ) {
            if( $return == "id" ) {
                return $payment_intent_id;
            } else {
                return \Stripe\PaymentIntent::retrieve( $payment_intent_id );
            }
        }
        
        $price = get_post_meta( $payment_id, "_adverts_payment_total", true );
        $stripe_customer = get_user_meta( get_current_user_id(), Core::get_customer_meta_key_name(), true );
        
        $intent_array = array(
            'amount' => $this->amount_to_int( $price ),
            'currency' => strtolower( adverts_config( 'config.currency_code' ) ),
            'setup_future_usage' => 'off_session'
        );
        
        if( $stripe_customer ) {
            $intent_array["customer"] = $stripe_customer;
        }
        
        $intent = \Stripe\PaymentIntent::create( $intent_array );

        add_post_meta( $payment_id, '_adverts_payment_intent_id', $intent->id );
        adext_payments_log( $payment_id, sprintf( __( "New Payment Intent Generated: <strong>%s</strong>", "wpadverts-stripe" ), $intent->id ) );
        
        if( $return == "id" ) {
            return $intent->id;
        } else {
            return $intent;
        }
    }
    
    /**
     * Sets default values for Stripe form
     * 
     * This function checks if current payment form is Stripe. If so and 
     * the $data is empty then it sets default values for contact person and email fields.
     * 
     * The function will try to get the details from payment object first (if it exists).
     * 
     * @param   Adverts_Form    $form   Instance of form.
     * @param   array           $data   User submitted form values ( key => value )
     * @return  Adverts_Form            Modified instance of form.
     */
    public function bind( $form, $data ) {
    
        $scheme = $form->get_scheme();

        if( $scheme["name"] != "adverts-stripe" ) {
            return $form;
        }

        if( empty( $data ) && adverts_request( "action" ) == "adext_payments_render" ) {

            if( adverts_request( "payment_id" ) ) {
                $object = get_post( adverts_request( "payment_id" ) );
            } else if(adverts_request( "object_id" ) ) {
                $object = get_post( adverts_request( "object_id" ) );
            } else {
                return $form;
            }

            $form->set_value( "adverts_person", get_post_meta( $object->ID, "adverts_person", true ) );
            $form->set_value( "adverts_email", get_post_meta( $object->ID, "adverts_email", true ) );
        }

        return $form;
    }
    
}
