<?php

namespace POPxPMPro\Providers;

use WcElectronInvoice\Providers\DateTimeProvider;
use function WcElectronInvoice\Functions\getPaymentMethodInvoiceCode;

defined( 'ABSPATH' ) || die( 'Not allowed.' );

class Order extends \WcElectronInvoice\Providers\Order {

    /**
     * @var \MemberOrder
     *
     */
    protected $order;

    function set_order( $order ) {
        $this->order = $order;
    }

    function get_id() {
        return $this->order->id;
    }

    function set_id() {
        $this->id = $this->order->id;
    }

    function set_payment_method() {
        $this->payment_method = $this->get_payment_method();
    }

    function get_provider() {
        return $this->provider->name();
    }

    function get_provider_label() {
        return $this->provider->get_label();
    }

    function set_data() {
        //$this->data = $this->order->get_data( $this->get_id() );
    }

    function get_data() {
        global $pmpro_gateways;

        $data['id']        = $this->get_id();
        $data['parent_id'] = $this->get_parent_id();
        $data['status']    = $this->get_status();

        $data['date_created']   = $this->get_date_created();
        $data['date_modified']  = $this->get_date_modified();
        $data['date_completed'] = $this->get_date_completed();

        $data['billing']        = $this->get_billing_data();
        $data['provider']       = $this->get_provider();
        $data['provider_label'] = $this->get_provider_label();
        $data['order_type']     = $this->get_type();

        // currency
        $data['currency']        = $this->get_currency();
        $data['currency_symbol'] = $this->get_currency_symbol( $data['currency'] );

        // customer user agent
        $data['customer_user_agent'] = '';

        // customer order note
        $data['customer_note'] = $this->order->notes;

        // payment method
        $data['payment_method']       = $this->get_payment_method();
        $data['payment_method_title'] = $pmpro_gateways[ $data['payment_method'] ] ?? $data['payment_method'];

        // shipping
        $data['shipping_total'] = 0;
        $data['shipping_tax']   = 0;
        $data['shipping']       = [];

        // total
        $data['total'] = $this->get_total();

        // discount and discount tax
        $data['discount_total'] = $this->get_discount_total();
        $data['discount_tax']   = $this->get_discount_tax();

        // cart tax
        $data['cart_tax'] = $this->get_cart_tax();

        // total tax
        $data['total_tax'] = $this->get_total_tax();
        $data['taxes']     = [
            'subtotal' => [ 1 => $this->get_total_tax() ],
            'total'    => [ 1 => $this->get_total_tax() ],
        ];

        // create via
        $data['created_via'] = '';

        // payment completed
        $data['date_paid'] = $this->get_date_paid();

        return $data;
    }

    function get_meta( $key, $single = true ) {

        switch ( $key ) {
            case '_billing_choice_type':
                return $this->get_billing_choice_type();
            default:
                return get_pmpro_membership_order_meta( $this->id, $key, $single );
        }

    }

    function update_meta( $key, $value ) {
        return update_pmpro_membership_order_meta( $this->id, $key, $value );
    }

    function delete_meta( $key ) {
        return delete_pmpro_membership_order_meta( $this->id, $key );
    }

    function get_total() {
        return $this->order->total;
    }

    function get_total_refunded() {
        $status = $this->get_status();
        switch ( $status ) {
            case 'refunded':
                return $this->get_total();

            default:
                return 0;
        }
    }

    function get_refunds() {
        if ( 'refunded' !== (string) $this->order->status ) {
            return [];
        }

        return [
            new OrderRefund( $this->order, $this->provider, $this->tax_provider ),
        ];
    }

    function get_remaining_refund_amount() {
        $payment_status = $this->order->status;
        switch ( $payment_status ) {
            case 'refunded':
                return 0;

            default:
                return $this->get_total();
        }
    }

    function get_remaining_refund_items() {

        $status = $this->get_status();
        switch ( $status ) {
            case 'completed':
            case 'pending':
                return 1;
            case 'refunded':
                return 0;
        }

    }

    function get_refund_payment_method() {
        switch ( $this->get_payment_method() ) {
            case 'stripe':
                return getPaymentMethodInvoiceCode('stripe');
            case 'paypal':
            case 'paypalexpress':
            case 'paypalstandard':
                return getPaymentMethodInvoiceCode('paypal');
            case 'check':
                return getPaymentMethodInvoiceCode('bacs');
            default:
                // Return fallback MP08 code
                return getPaymentMethodInvoiceCode('unknown');
        }
    }

    function get_total_qty_refunded() {
        $status = $this->get_status();
        switch ( $status ) {
            case 'completed':
            case 'pending':
                return 0;
            case 'refunded':
                return 1;
        }
    }

    function get_qty_refunded_for_item() {
        // zero. this is not a refund order.
        return 0;
    }

    function get_total_refunded_for_item( $item_id, $item_type ) {
        return $this->order->amount;
    }

    function get_tax_refunded_for_item( $item_id, $item_type ) {
        // taxes for a subscription item is the total tax
        return $this->get_total_tax();
    }

    function get_parent_id() {
        return $this->order->id;
    }

    private function get_billing_data() {
        $billing_data = [];

        // map POP fields from order column, order meta, user meta or user field
        $billing_map = [
            'first_name' => [
                'order_column' => 'billing_first_name',
                'user_meta'    => 'first_name',
                'user_field'   => false,
            ],
            'last_name'  => [
                'order_column' => 'billing_last_name',
                'user_meta'    => 'last_name',
                'user_field'   => false
            ],
            'email'      => [
                'order_column' => 'billing_email',
                'user_meta'    => false,
                'user_field'   => 'user_email'
            ],
            'company'    => [
                'order_column' => 'billing_company',
                'order_meta'   => 'billing_company',
                'user_meta'    => 'billing_company',
                'user_field'   => false
            ],
            'address_1'  => [
                'order_column'        => 'billing_street',
                'order_meta'          => 'billing_address1',
                'user_meta'           => 'billing_address1',
                'user_meta_fallbacks' => [ 'pmpro_baddress1' ],
                'user_field'          => false
            ],
            'city'       => [
                'order_column'        => 'billing_city',
                'order_meta'          => 'billing_city',
                'user_meta'           => 'billing_city',
                'user_meta_fallbacks' => [ 'pmpro_bcity' ],
                'user_field'          => false
            ],
            'state'      => [
                'order_column'        => 'billing_state',
                'order_meta'          => 'billing_state',
                'user_meta'           => 'billing_state',
                'user_meta_fallbacks' => [ 'pmpro_bstate' ],
                'user_field'          => false
            ],
            'postcode'   => [
                'order_column'        => 'billing_zip',
                'order_meta'          => 'billing_postcode',
                'user_meta'           => 'billing_postcode',
                'user_meta_fallbacks' => [ 'pmpro_bzipcode' ],
                'user_field'          => false
            ],
            'country'    => [
                'order_column'        => 'billing_country',
                'order_meta'          => 'billing_country',
                'user_meta'           => 'billing_country',
                'user_meta_fallbacks' => [ 'pmpro_bcountry' ],
                'user_field'          => false
            ],
        ];

        $user_id = $this->get_user_id();
        foreach ( $billing_map as $key => $map ) {
            if ( empty( $billing_data[ $key ] ) && isset( $map['order_meta'] ) ) {
                $billing_data[ $key ] = get_pmpro_membership_order_meta( $this->id, $map['order_meta'], true );
            }

            if ( empty( $billing_data[ $key ] ) && isset( $map['order_column'] ) ) {
                // if the order_column is something like "billing_anything", then you should take $this->order->billing->anything
                if ( 0 === strpos( $map['order_column'], 'billing_' ) ) {
                    $billing_field_name   = str_replace( 'billing_', '', $map['order_column'] );
                    $billing_data[ $key ] = $this->order->billing->{$billing_field_name} ?? '';
                } else {
                    $billing_data[ $key ] = $this->order->{$map['order_column']};
                }
            }

            if ( empty( $billing_data[ $key ] ) && isset( $map['order_meta'] ) ) {
                $billing_data[ $key ] = get_pmpro_membership_order_meta( $this->id, $map['order_meta'], true );
            }

            if ( empty( $billing_data[ $key ] ) && $map['user_meta'] ) {
                $billing_data[ $key ] = get_user_meta( $user_id, $map['user_meta'], true );
            }

            if ( empty( $billing_data[ $key ] ) && ! empty( $map['user_meta_fallbacks'] ) ) {
                foreach ( $map['user_meta_fallbacks'] as $meta_key ) {
                    $billing_data[ $key ] = get_user_meta( $user_id, $meta_key, true );
                    if ( ! empty( $billing_data[ $key ] ) ) {
                        break;
                    }
                }
            }

            if ( empty( $billing_data[ $key ] ) && $map['user_field'] ) {
                $user_data = get_userdata( $user_id );
                if ( $user_data ) {
                    $user_data = (array) $user_data->data;
                }

                $billing_data[ $key ] = $user_data[ $map['user_field'] ] ?? '';
            }

            if ( empty( $billing_data[ $key ] ) && isset( $map['default'] ) ) {
                $billing_data[ $key ] = $map['default'];
            }
        }

        return $billing_data;
    }

    private function get_invoice_data() {
        $invoice_data = [];

        // map POP fields from order column, order meta, user meta or user field
        $billing_map = [
            'vat_number'   => [
                'order_meta' => 'billing_vat_number',
                'user_meta'  => 'billing_vat_number',
                'user_field' => false
            ],
            'tax_code'     => [
                'order_meta' => 'billing_tax_code',
                'user_meta'  => 'billing_tax_code',
                'user_field' => false
            ],
            'choice_type'  => [
                'order_meta' => 'billing_choice_type',
                'user_meta'  => 'billing_choice_type',
                'user_field' => false,
                'default'    => 'invoice'
            ],
            'invoice_type' => [
                'order_meta' => 'billing_invoice_type',
                'user_meta'  => 'billing_invoice_type',
                'user_field' => false,
                'default'    => 'private',
            ],
            'sdi_type'     => [
                'order_meta' => 'billing_sdi_type',
                'user_meta'  => 'billing_sdi_type',
                'user_field' => false
            ],
        ];

        $user_id = $this->get_user_id();
        foreach ( $billing_map as $key => $map ) {
            if ( empty( $invoice_data[ $key ] ) && isset( $map['order_meta'] ) ) {
                $invoice_data[ $key ] = get_pmpro_membership_order_meta( $this->id, $map['order_meta'], true );
            }

            if ( empty( $invoice_data[ $key ] ) && $map['user_meta'] ) {
                $invoice_data[ $key ] = get_user_meta( $user_id, $map['user_meta'], true );
            }

            if ( empty( $invoice_data[ $key ] ) && $map['user_field'] ) {
                $user_data            = (array) get_userdata( $user_id );
                $invoice_data[ $key ] = $user_data[ $map['user_field'] ] ?? '';
            }

            if ( empty( $invoice_data[ $key ] ) && isset( $map['default'] ) ) {
                $invoice_data[ $key ] = $map['default'];
            }
        }

        /*
        var_dump( $user_id );
        var_dump( get_user_meta( $user_id ));
        var_dump( get_pmpro_membership_order_meta( $this->id ) );
        exit;
        */

        // var_dump( $user_id, $invoice_data ); exit;
        return $invoice_data;
    }

    function get_billing_choice_type() {
        return $this->get_invoice_data()['choice_type'];
    }

    function get_billing_first_name() {
        return $this->get_billing_data()['first_name'];
    }

    function get_billing_last_name() {
        return $this->get_billing_data()['last_name'];
    }

    function get_billing_company() {
        return $this->get_billing_data()['company'];
    }

    function get_billing_email() {
        return $this->get_billing_data()['email'];
    }

    function get_billing_phone() {
        // PMS doesn't have phone field
        return '';
    }

    function get_billing_address_1() {
        return $this->get_billing_data()['address_1'];
    }

    function get_billing_address_2() {
        return '';
    }

    function get_billing_postcode() {
        return $this->get_billing_data()['postcode'];
    }

    function get_billing_country() {
        return $this->get_billing_data()['country'];
    }

    function get_billing_city() {
        return $this->get_billing_data()['city'];
    }

    function get_billing_state() {
        return $this->get_billing_data()['state'];
    }

    function get_user_id() {
        return (int) $this->order->user_id;
    }

    /**
     * @return string shop_order or shop_order_refund (to distinguish between order and refund)
     */
    function get_type() {
        return 'shop_order';
    }

    function get_type_label( $type ) {
        return __( 'Payment', WC_EL_INV_TEXTDOMAIN );
    }

    function get_items( $type = 'line_item' ) {
        $items = array();

        switch ( $type ) {
            case 'line_item':
                $items[] = new OrderItem( $this->order );
                break;
            case 'fee':
                $fees           = [];
                $stampDutyValue = $this->get_meta('stamp_duty_fee_value');
                if (! empty($stampDutyValue)) {
                    $fee            = new \stdClass();
                    $fee->id        = 'stamp_duty';
                    $fee->name      = $this->get_meta('stamp_duty_fee_name') ?: 'Imposta di Bollo';
                    $fee->total     = $stampDutyValue;
                    $fee->total_tax = 0;
                    $fee->tax_class = '';
                    $fees[]         = $fee;
                }

                $rivalsaValue = $this->get_meta('rivalsa_fee_value');
                if (! empty($rivalsaValue)) {
                    $fee            = new \stdClass();
                    $fee->id        = 'rivalsa';
                    $fee->name      = $this->get_meta('rivalsa_fee_name') ?: 'Rivalsa INPS';
                    $fee->total     = $rivalsaValue;
                    $fee->total_tax = 0;
                    $fee->tax_class = '';
                    $fees[]         = $fee;
                }

                foreach ($fees as $f) {
                    $items[] = $f;
                }

                break;
            case 'shipping':
                // no shipping for digital subscription
                break;
            case 'tax':
                $items[] = new TaxOrderItem( $this->order );
                break;
            case 'coupon':
                // TODO: Implement data for coupon?
                break;
        }

        return $items;
    }

    function get_invoice_sent( $order_id = '' ) {
        $order_id = $order_id ?: $this->id;
        $value    = get_pmpro_membership_order_meta( $order_id, 'invoice_sent', true );
        if ( '' === $value || null === $value ) {
            $value = get_pmpro_membership_order_meta( $order_id, '_invoice_sent', true );
        }
        if ( is_bool( $value ) ) {
            return $value ? 'sent' : 'no_sent';
        }

        return $value;
    }

    function get_invoice_sent_timestamp( $order_id = '' ) {
        $order_id = empty( $order_id ) ? $this->id : $order_id;
        $value    = get_pmpro_membership_order_meta( $order_id, 'invoice_sent_timestamp', true );
        if ( '' === $value || null === $value ) {
            $value = get_pmpro_membership_order_meta( $order_id, '_invoice_sent_timestamp', true );
        }

        return $value;
    }

    function set_invoice_sent( $sent, $order_id = '' ) {
        $order_id = empty( $order_id ) ? $this->id : $order_id;
        update_pmpro_membership_order_meta( $order_id, '_invoice_sent', $sent );

        return update_pmpro_membership_order_meta( $order_id, 'invoice_sent', $sent );
    }

    function set_invoice_sent_timestamp( $timestamp, $order_id = '' ) {
        $order_id = empty( $order_id ) ? $this->id : $order_id;
        update_pmpro_membership_order_meta( $order_id, '_invoice_sent_timestamp', $timestamp );
        update_pmpro_membership_order_meta( $order_id, 'invoice_sent_timestamp', $timestamp );
    }

    function get_billing_invoice_type() {
        return $this->get_invoice_data()['invoice_type'];
    }

    function get_billing_tax_code() {
        return $this->get_invoice_data()['tax_code'];
    }

    function get_sdi_type() {
        return $this->get_invoice_data()['sdi_type'];
    }

    function get_vat_number() {
        return $this->get_invoice_data()['vat_number'];
    }

    function get_order_number_invoice() {
        return $this->get_meta( 'order_number_invoice');
    }

    function get_edit_user_url() {
        return add_query_arg(
            array(
                'page'  => 'pmpro-member',
                'user_id' => $this->get_user_id()
            ),
            admin_url( 'admin.php' )
        );

    }

    function get_edit_order_url() {

        return add_query_arg(
            array(
                'page'  => 'pmpro-orders',
                'id' => $this->get_id()
            ),
            admin_url( 'admin.php' )
        );

    }

    function get_status() {

        $status = $this->order->status;

        // map pms payment status to woocommerce order status
        switch ( $status ) {
            case 'cancelled':
            case 'success':
                return 'completed';
            case 'review':
            case 'pending':
                return 'processing';
            case 'error':
                return 'failed';
            case 'refunded':
                return 'refunded';
            case 'token':
            default:
                return 'unknown';
        }
    }

    function get_currency() {
        // or maybe pmpro_get_currency( $pmpro_currency )['name'];
        global $pmpro_currency;

        return $pmpro_currency;
    }

    function get_currency_symbol( $currency ) {
        global $pmpro_currency_symbol;

        return $pmpro_currency_symbol;
    }

    function get_payment_method() {
        switch ( $this->order->gateway ) {
            case 'stripe':
                return 'stripe';
            case 'paypal':
            case 'paypalexpress':
            case 'paypalstandard':
                return 'paypal';
            case 'check':
                return 'bank_transfer';
            default:
                return 'unknown';
        }
    }

    function has_status( $status ) {
        return $this->get_status() === $status;
    }

    function get_date_completed() {
        $invoiceDate = get_pmpro_membership_order_meta( $this->id, 'order_date_invoice', true );

        if ( $invoiceDate ) {
            try {
                return new DateTimeProvider( $invoiceDate );
            } catch ( \Exception $exception ) {
                // Fall through to creation date if the stored value is invalid.
            }
        }

        return $this->get_date_created();
    }

    function get_date_paid() {
        $date_completed = get_pmpro_membership_order_meta( $this->id, 'date_paid', true );
        if( ! $date_completed ){
            $date_completed = $this->get_date_created();
        }

        return $date_completed;
    }

    /**
     * Get the payment modified date.
     * @return DateTimeProvider
     */
    function get_date_modified() {
        // PMPro does not keep track of status changes into any kind of logs.
        return $this->get_date_created();
    }

    function get_date_created() {
        return new DateTimeProvider( date( 'Y-m-d H:i:s', $this->order->getTimestamp() ) );
    }

    function get_shipping_total() {
        // it's a digital product, no shipping
        return 0;
    }

    function get_shipping_tax() {
        // it's a digital product, no shipping
        return 0;
    }

    function get_nature_rc() {
        return \get_pmpro_membership_order_meta( $this->id, 'nature_rc', true );
    }

    function get_ref_norm_rc() {
        return \get_pmpro_membership_order_meta( $this->id, 'ref_norm_rc', true );
    }

    /**
     * Get the discount total.
     * @return mixed
     */
    function get_discount_total() {
        return 0;
    }

    /**
     * Get the discount tax.
     * @return float|int
     */
    function get_discount_tax() {
        return 0;
    }

    /**
     * Get the cart tax.
     * @return int
     */
    private function get_cart_tax() {
        // cart tax set to 0
        // what's cart tax???
        return 0;
    }

    /**
     * Get the total tax for the payment.
     * @return float|int
     */
    function get_total_tax() {
        return $this->order->tax;
    }

    function set_date_completed( $timestamp ) {
        // nothing to do here
    }

    /**
     * Get payment logs.
     *
     * @return array
     */
    function get_log() {
        return [];
    }

    /**
     * Get payment refund data from the logs.
     * @return mixed|void
     */
    function get_refunded_data() {
        return [];
    }

    /**
     * Get completed payment data from the logs.
     * @return mixed|void
     */
    function get_completed_data() {
        return [];
    }

    function save() {
        $this->order->saveOrder();
    }

    function get_invoice_type() {
        return $this->get_billing_invoice_type();
    }
}
