<?php
namespace Bright_Deposits_For_WooCommerce\Core;

use Bright_Deposits_For_WooCommerce\Helpers\Helper;

/**
 * @package Bright_Deposits_For_WooCommerce\Core
 * @since 1.0.0
 * @author Bright Plugins
 * Description: Represents a deposit order in WooCommerce.
 */
class OrderDeposit extends \WC_Order {

    /**
     * Get internal type.
     * @since 1.0.0
     * @return string
     */
    public function get_type() {
        return 'shop_deposit';
    }

    /**
     * Get customer_id.
     * @since 1.0.0
     * @param  string $context What the value is for. Valid values are view and edit.
     * @return int
     */
    public function get_customer_id( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_customer_id( $context );
        }

        return $this->get_prop( 'customer_id', $context );
    }

    /**
     * Alias for get_customer_id().
     * @since 1.0.0
     * @param  string $context What the value is for. Valid values are view and edit.
     * @return int
     */
    public function get_user_id( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_user_id( $context );
        }

        return $this->get_prop( 'customer_id', $context );
    }

    /**
     * Get the user associated with the order. False for guests.
     * @since 1.0.0
     * @return WP_User|false
     */
    public function get_user() {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_user();
        }

        return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
    }

    /**
     * Gets a prop for a getter method.
     * @since 1.0.0
     * @param  string  $prop    Name of prop to get.
     * @param  string  $address billing or shipping.
     * @param  string  $context What the value is for. Valid values are view and edit.
     * @return mixed
     */
    protected function get_address_prop( $prop, $address = 'billing', $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_address_prop( $prop, $address, $context );
        }

        $value = null;

        if ( array_key_exists( $prop, $this->data[$address] ) ) {
            $value = isset( $this->changes[$address][$prop] ) ? $this->changes[$address][$prop] : $this->data[$address][$prop];

            if ( 'view' === $context ) {
                // Uses WooCommerce's dynamic "woocommerce_order_get_{$address}_{$prop}" filter naming for compatibility.
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
                $value = apply_filters( $this->get_hook_prefix() . $address . '_' . $prop, $value, $this );
            }
        }
        return $value;
    }

    /**
     * Get billing first name.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_first_name( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_first_name( $context );
        }

        return $this->get_address_prop( 'first_name', 'billing', $context );
    }

    /**
     * Get billing last name.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_last_name( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_last_name( $context );
        }

        return $this->get_address_prop( 'last_name', 'billing', $context );
    }

    /**
     * Get billing company.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_company( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_company( $context );
        }

        return $this->get_address_prop( 'company', 'billing', $context );
    }

    /**
     * Get billing address line 1.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_address_1( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_address_1( $context );
        }

        return $this->get_address_prop( 'address_1', 'billing', $context );
    }

    /**
     * Get billing address line 2.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_address_2( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_address_2( $context );
        }

        return $this->get_address_prop( 'address_2', 'billing', $context );
    }

    /**
     * Get billing city.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_city( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_city( $context );
        }

        return $this->get_address_prop( 'city', 'billing', $context );
    }

    /**
     * Get billing state.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_state( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_state( $context );
        }

        return $this->get_address_prop( 'state', 'billing', $context );
    }

    /**
     * Get billing postcode.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_postcode( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_postcode( $context );
        }

        return $this->get_address_prop( 'postcode', 'billing', $context );
    }

    /**
     * Get billing country.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_country( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_country( $context );
        }

        return $this->get_address_prop( 'country', 'billing', $context );
    }

    /**
     * Get billing email.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_email( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_email( $context );
        }

        return $this->get_address_prop( 'email', 'billing', $context );
    }

    /**
     * Get billing phone.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_billing_phone( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_billing_phone( $context );
        }

        return $this->get_address_prop( 'phone', 'billing', $context );
    }

    /**
     * Get shipping first name.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_first_name( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_first_name( $context );
        }

        return $this->get_address_prop( 'first_name', 'shipping', $context );
    }

    /**
     * Get shipping_last_name.
     * @since 1.0.0     
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_last_name( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_last_name( $context );
        }

        return $this->get_address_prop( 'last_name', 'shipping', $context );
    }

    /**
     * Get shipping company.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_company( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_company( $context );
        }

        return $this->get_address_prop( 'company', 'shipping', $context );
    }

    /**
     * Get shipping address line 1.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_address_1( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_address_1( $context );
        }

        return $this->get_address_prop( 'address_1', 'shipping', $context );
    }

    /**
     * Get shipping address line 2.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_address_2( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_address_2( $context );
        }

        return $this->get_address_prop( 'address_2', 'shipping', $context );
    }

    /**
     * Get shipping city.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_city( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_city( $context );
        }

        return $this->get_address_prop( 'city', 'shipping', $context );
    }

    /**
     * Get shipping state.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_state( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_state( $context );
        }

        return $this->get_address_prop( 'state', 'shipping', $context );
    }

    /**
     * Get shipping postcode.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_postcode( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_postcode( $context );
        }

        return $this->get_address_prop( 'postcode', 'shipping', $context );
    }

    /**
     * Get shipping country.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_shipping_country( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_country( $context );
        }

        return $this->get_address_prop( 'country', 'shipping', $context );
    }

    /**
     * Get customer ip address.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_customer_ip_address( $context = 'view' ) {
        $ip_address = $this->get_prop( 'customer_ip_address', $context );

        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to get the customer ip address.
         * @since 1.0.0
         * @param string    $ip_address The customer ip address.
         * @param \WC_Order $this        The order object.
         * @param string    $context     The context.
         */
        return apply_filters( 'bdfwbp_deposit_get_customer_ip_address', $ip_address, $this, $context );
    }

    /**
     * Get customer user agent.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_customer_user_agent( $context = 'view' ) {
        $user_agent = $this->get_prop( 'customer_user_agent', $context );

        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to get the customer user agent.
         * @since 1.0.0
         * @param string    $user_agent The customer user agent.
         * @param \WC_Order $this        The order object.
         * @param string    $context     The context.
         */
        return apply_filters( 'bdfwbp_deposit_get_customer_user_agent', $user_agent, $this, $context );
    }

    /**
     * Get created via.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_created_via( $context = 'view' ) {
        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to get the created via.
         * @since 1.0.0
         * @param string    $created_via The created via.
         * @param \WC_Order $this        The order object.
         * @param string    $context     The context.
         */
        return apply_filters( 'bdfwbp_deposit_get_created_via', 'admin', $this, $context );
    }

    /**
     * Get customer note.
     * @since 1.0.0
     * @param  string   $context What the value is for. Valid values are view and edit.
     * @return string
     */
    public function get_customer_note( $context = 'view' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_customer_note( $context );
        }

        return $this->get_prop( 'customer_note', $context );
    }

    /**
     * Returns the requested address in raw, non-formatted way.
     * Note: Merges raw data with get_prop data so changes are returned too.
     * @since 1.0.0
     * @since  2.4.0
     *
     * @param  string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
     * @return array  The stored address after filter.
     */
    public function get_address( $type = 'billing' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_address( $type );
        }

        return apply_filters( 'woocommerce_get_order_address', array_merge( $this->data[$type], $this->get_prop( $type, 'view' ) ), $type, $this );
    }

    /**
     * Gets the order number for display (by default, order ID).
     * @since 1.0.0
     * @return string
     */
    public function get_order_number() {
        if ( is_order_received_page() && did_action( 'woocommerce_before_thankyou' ) && !did_action( 'woocommerce_thankyou' ) ) {
            return (string) apply_filters( 'woocommerce_order_number', $this->get_parent_id(), $this );
        }
        return (string) apply_filters( 'woocommerce_order_number', $this->get_id(), $this );
    }

    /**
     * Get a formatted shipping address for the order.
     * @since 1.0.0
     * @return string
     */
    public function get_shipping_address_map_url() {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_shipping_address_map_url();
        }

        $address = $this->get_address( 'shipping' );

        // Remove name and company before generate the Google Maps URL.
        unset( $address['first_name'], $address['last_name'], $address['company'] );

        $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', $address, $this );

        return apply_filters( 'woocommerce_shipping_address_map_url', 'https://maps.google.com/maps?&q=' . rawurlencode( implode( ', ', $address ) ) . '&z=16', $this );
    }

    /**
     * Get a formatted billing full name.
     * @since 1.0.0
     * @return string
     */
    public function get_formatted_billing_full_name() {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_formatted_billing_full_name();
        }

        /* translators: 1: first name 2: last name */
        $name = sprintf( _x( '%1$s %2$s', 'full name', 'bright-deposits-for-woocommerce' ), $this->get_billing_first_name(), $this->get_billing_last_name() );

        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to get the formatted billing full name.
         * @since 1.0.0
         * @param string    $name The formatted billing full name.
         * @param \WC_Order $this The order object.
         */
        return apply_filters( 'bdfwbp_deposit_get_formatted_billing_full_name', $name, $this );
    }

    /**
     * Get a formatted shipping full name.
     * @since 1.0.0
     * @return string
     */
    public function get_formatted_shipping_full_name() {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_formatted_shipping_full_name();
        }

        /* translators: 1: first name 2: last name */
        $name = sprintf( _x( '%1$s %2$s', 'full name', 'bright-deposits-for-woocommerce' ), $this->get_shipping_first_name(), $this->get_shipping_last_name() );

        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to get the formatted shipping full name.
         * @since 1.0.0
         * @param string    $name The formatted shipping full name.
         * @param \WC_Order $this The order object.
         */
        return apply_filters( 'bdfwbp_deposit_get_formatted_shipping_full_name', $name, $this );
    }

    /**
     * Get a formatted billing address for the order.
     * @since 1.0.0
     * @param  string   $empty_content Content to show if no address is present. @since 3.3.0.
     * @return string
     */
    public function get_formatted_billing_address( $empty_content = '' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_formatted_billing_address( $empty_content );
        }

        $address = apply_filters( 'woocommerce_order_formatted_billing_address', $this->get_address( 'billing' ), $this );
        $address = WC()->countries->get_formatted_address( $address );

        return $address ? $address : $empty_content;
    }

    /**
     * Get a formatted shipping address for the order.
     * @since 1.0.0
     * @param  string   $empty_content Content to show if no address is present. @since 3.3.0.
     * @return string
     */
    public function get_formatted_shipping_address( $empty_content = '' ) {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->get_formatted_shipping_address( $empty_content );
        }

        $address = '';

        if ( $this->has_shipping_address() ) {
            $address = apply_filters( 'woocommerce_order_formatted_shipping_address', $this->get_address( 'shipping' ), $this );
            $address = WC()->countries->get_formatted_address( $address );
        }

        return $address ? $address : $empty_content;
    }

    /**
     * Returns true if the order has a billing address.
     * @since 1.0.0
     * @return boolean
     */
    public function has_billing_address() {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->has_billing_address();
        }

        $has_billing_address = $this->get_billing_address_1() || $this->get_billing_address_2();

        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to check if the order has a billing address.
         * @since 1.0.0
         * @param boolean   $has_billing_address Whether the order has a billing address.
         * @param \WC_Order $this                 The order object.
         */
        return apply_filters( 'bdfwbp_deposit_has_billing_address', $has_billing_address, $this );
    }

    /**
     * Returns true if the order has a shipping address.
     * @since 1.0.0
     * @return boolean
     */
    public function has_shipping_address() {
        $parent = wc_get_order( $this->get_parent_id() );
        if ( $parent ) {
            return $parent->has_shipping_address();
        }

        $has_shipping_address = $this->get_shipping_address_1() || $this->get_shipping_address_2();

        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to check if the order has a shipping address.
         * @since 1.0.0
         * @param boolean   $has_shipping_address Whether the order has a shipping address.
         * @param \WC_Order $this                 The order object.
         */
        return apply_filters( 'bdfwbp_deposit_has_shipping_address', $has_shipping_address, $this );
    }

    /**
     * Check if the order is editable.
     * @since 1.0.0
     * @return boolean
     */
    public function is_editable() {
        /**
         * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to check if the order is editable.
         * @since 1.0.0
         * @param boolean   $is_editable Whether the order is editable.
         * @param \WC_Order $this        The order object.
         */
        return apply_filters( 'bdfwbp_deposit_payment_editable', false, $this->get_id() );
    }

    /**
     * Get order item totals.
     * @param $tax_display
     * @since 1.0.0
     */
    public function get_order_item_totals( $tax_display = '' ) {
        if ( did_action( 'woocommerce_order_details_after_order_table_items' ) ) {
            $total_rows = array( 'order_total' => array(
                'label' => Helper::getOptionValue( 'bdfw_partial_payment_amount_label' ),
                'value' => $this->get_formatted_order_total( $tax_display ),
            ) );
            return apply_filters( 'bdfwbp_deposit_get_order_item_totals_thankyou', $total_rows, $this, $tax_display );
        }

        $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
        $total_rows  = array();

        $this->add_order_item_totals_fee_rows( $total_rows, $tax_display );
        $this->add_order_item_totals_total_row( $total_rows, $tax_display );

        /**
         * BDFWBP_CUSTOM_ACTION_HOOK: Allows developers to add custom rows to the order item totals.
         * @since 1.0.0
         * @param array     $total_rows  The total rows.
         * @param \WC_Order $this        The order object.
         * @param string    $tax_display The tax display mode.
         */
        do_action( 'bdfwbp_deposit_get_order_item_totals', $total_rows, $this, $tax_display );

        return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this, $tax_display );
    }
}
