<?php

namespace POPxPMPro\Providers;

use WcElectronInvoice\Providers\OrdersProviderAbstract;

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

class OrdersProvider extends OrdersProviderAbstract {

    /**
     * @inheritDoc
     */
    public function getOrders( $args = array(), $onlyCount = false ) {
        global $wpdb;

        $orders      = array();
        $orderType   = '';

        if ( empty( $args ) ) {
            $args = array(
                'status' => OrdersProviderAbstract::ORDERS_DEFAULT_LIST_STATUSES
            );
        }

        $args = array_merge(
            array(
                'status'  => OrdersProviderAbstract::ORDERS_DEFAULT_LIST_STATUSES,
                'orderby' => 'date',
                'order'   => 'DESC',
                'limit'   => -1,
            ),
            $args
        );

        $args = $this->mapArgs( $args );
        if ( isset( $args['type'] ) ) {
            $orderType = sanitize_key( (string) $args['type'] );
        }

        // PMS order query extracts payments using only one status
        // so we need to query for each status separately
        // and merge the results
        foreach ( $args['status'] as $status ) {
            // TODO should also include refunded orders?
            $conditions = [ "status = '{$status}'" ];

            if ( ! empty( $args['timestamp'] ) && ! is_array($args['timestamp']) ) {
                $conditions[] = "timestamp >= '" . esc_sql( $args['timestamp'] ) . "'";
            } elseif(! empty( $args['timestamp'] )) {
                $start = isset( $args['timestamp'][0] ) ? $args['timestamp'][0] : null;
                $end = isset( $args['timestamp'][1] ) ? $args['timestamp'][1] : null;
                if($start) {
                    $conditions[] = "timestamp >= '" . esc_sql( $start ) . "'";
                }
                if($end) {
                    $conditions[] = "timestamp <= '" . esc_sql( $end ) . "'";
                }
            }
            $where = implode( ' AND ', $conditions );

            $mysql      = "SELECT id FROM {$wpdb->prefix}pmpro_membership_orders WHERE {$where} ORDER BY " . esc_sql( $args['orderby'] ) . " " . esc_sql( $args['order'] ) . " LIMIT " . intval( $args['limit'] );
            $orders_ids = $wpdb->get_col( $mysql );

            foreach ( $orders_ids as $order_id ) {
                $order = $this->getOrder( $order_id );
                if ( ! $order ) {
                    continue;
                }

                if ( 'shop_order_refund' === $orderType ) {
                    foreach ( $order->get_refunds() as $refund ) {
                        $orders[] = $refund;
                    }
                    continue;
                }

                $orders[] = $order;

                if ( '' === $orderType ) {
                    foreach ( $order->get_refunds() as $refund ) {
                        $orders[] = $refund;
                    }
                }
            }
        }

        return $orders;
    }

    /**
     * @inheritDoc
     */
    public function getOrderSummaries( $args = array() ) {
        global $wpdb;

        $summaries    = array();
        $orderType    = '';
        $summaryIndex = array();

        if ( empty( $args ) ) {
            $args = array(
                'status' => OrdersProviderAbstract::ORDERS_DEFAULT_LIST_STATUSES
            );
        }

        $args = array_merge(
            array(
                'status'  => OrdersProviderAbstract::ORDERS_DEFAULT_LIST_STATUSES,
                'orderby' => 'date',
                'order'   => 'DESC',
                'limit'   => -1,
            ),
            $args
        );

        $args = $this->mapArgs( $args );
        if ( isset( $args['type'] ) ) {
            $orderType = sanitize_key( (string) $args['type'] );
        }

        foreach ( $args['status'] as $status ) {
            $conditions = [ "status = '{$status}'" ];

            if ( ! empty( $args['timestamp'] ) && ! is_array( $args['timestamp'] ) ) {
                $conditions[] = "timestamp >= '" . esc_sql( $args['timestamp'] ) . "'";
            } elseif ( ! empty( $args['timestamp'] ) ) {
                $start = isset( $args['timestamp'][0] ) ? $args['timestamp'][0] : null;
                $end = isset( $args['timestamp'][1] ) ? $args['timestamp'][1] : null;
                if ( $start ) {
                    $conditions[] = "timestamp >= '" . esc_sql( $start ) . "'";
                }
                if ( $end ) {
                    $conditions[] = "timestamp <= '" . esc_sql( $end ) . "'";
                }
            }

            if ( ! empty( $args['include'] ) && is_array( $args['include'] ) ) {
                $conditions[] = 'id IN (' . implode( ',', array_map( 'intval', $args['include'] ) ) . ')';
            }

            $where = implode( ' AND ', $conditions );
            $mysql = "SELECT id FROM {$wpdb->prefix}pmpro_membership_orders WHERE {$where} ORDER BY " . esc_sql( $args['orderby'] ) . " " . esc_sql( $args['order'] ) . " LIMIT " . intval( $args['limit'] );
            $orderIds = $wpdb->get_col( $mysql );

            foreach ( $orderIds as $orderId ) {
                $order = $this->getOrder( $orderId );
                if ( ! $order ) {
                    continue;
                }

                if ( 'shop_order_refund' === $orderType ) {
                    foreach ( $order->get_refunds() as $refund ) {
                        $summary = $this->buildRefundSummary( $refund, $order );
                        $summaryIndex[ $summary['document_key'] ] = $summary;
                    }
                    continue;
                }

                $summary = $this->buildOrderSummary( $order );
                $summaryIndex[ $summary['document_key'] ] = $summary;

                if ( '' === $orderType ) {
                    foreach ( $order->get_refunds() as $refund ) {
                        $refundSummary = $this->buildRefundSummary( $refund, $order );
                        $summaryIndex[ $refundSummary['document_key'] ] = $refundSummary;
                    }
                }
            }
        }

        foreach ( $summaryIndex as $summary ) {
            $summaries[] = $summary;
        }

        return $summaries;
    }

    /**
     * @param $orderId
     */
    public function getOrder($orderId)
    {
        return new Order(new \MemberOrder($orderId), $this, new TaxesProvider());
    }

    /**
     * @inheritDoc
     */
    public function name() {
        return 'pmpro';
    }

    /**
     * @inheritDoc
     *
     */
    public function get_label() {
        return __( 'PMPro', WC_EL_INV_TEXTDOMAIN );
    }

    /**
     * @param $args
     *
     * @return array|mixed
     */
    public function mapArgs( $args ) {

        // map the status to the ones used by WooCommerce
        if ( isset( $args['status'] ) ) {
            foreach ( $args['status'] as $key => $value ) {
                if ( $value == 'processing' ) {
                    unset( $args['status'][ $key ] );
                }
                if ( $value == 'completed' ) {
                    $args['status'][ $key ] = 'success';
                }
            }

            $args['status'][] = 'cancelled';
        }

        if ( isset( $args['orderby'] ) && $args['orderby'] == 'date' ) {
            $args['orderby'] = 'timestamp';
        }

        // map the date_created to date
        // date as array of dates, search for dates between the two dates
        // date as string, search for dates equal to the date
        if ( isset( $args['date_created'] ) ) {

            $dates = explode( '...', $args['date_created'] );
            foreach ( $dates as $key => $date ) {
                $timestamp = intval(preg_replace('/[^0-9]/', '', $date));
                $dates[ $key ] = date( 'Y-m-d H:i:s', $timestamp );
            }

            if ( sizeof( $dates ) < 2 ) {
                $dates = $dates[0];
            }

            unset( $args['date_created'] );
            $args['timestamp'] = $dates;

        }

        return $args;
    }

    /**
     * Build PMPro-specific refund summary metadata.
     *
     * @param \POPxPMPro\Providers\OrderRefund $refund
     * @param \POPxPMPro\Providers\Order       $parentOrder
     *
     * @return array<string, mixed>
     */
    private function buildRefundSummary( $refund, $parentOrder ) {
        $refunds = (array) $parentOrder->get_refunds();
        $latestRefund = ! empty( $refunds ) ? end( $refunds ) : null;

        return $this->buildOrderSummary( $refund, array(
            'parent_invoice_number'         => (string) $parentOrder->get_order_number_invoice(),
            'parent_invoice_sent'           => $parentOrder->get_invoice_sent( $parentOrder->get_id() ),
            'parent_invoice_sent_timestamp' => $parentOrder->get_invoice_sent_timestamp( $parentOrder->get_id() ),
            'refund_invoice_sent_timestamp' => $refund->get_invoice_sent_timestamp( $refund->get_id() ),
            'refund_number'                 => (string) $refund->get_order_number_invoice(),
            'refund_count'                  => count( $refunds ),
            'is_latest_refund'              => $latestRefund ? ( (int) $latestRefund->get_id() === (int) $refund->get_id() ) : true,
        ) );
    }

    /**
     * Save the tax rate and discount total in payment meta
     * on payment insertx
     *
     * @param $payment_id
     * @param $data
     *
     * @return void
     */
    public function on_payment_insert( $payment_id, $data ) {
        // Legacy handler intentionally disabled:
        // this method is not registered on any current hook, so keeping business logic
        // here creates dead code and stale static-analysis warnings.
        // If re-enabled in the future, restore logic and initialize tax settings via
        // TaxesProvider::get_tax_settings().
        return;
    }

    /**
     * Save the tax rate and discount total in payment meta
     * on payment update
     *
     * @param $payment
     * @param $order
     *
     * @return mixed
     */
    public function on_payment_admin_edit( $id, $data, $old_data ) {
        // Legacy handler intentionally disabled:
        // this method is not registered on any current hook, so keeping business logic
        // here creates dead code and stale static-analysis warnings.
        // If re-enabled in the future, restore logic and initialize tax settings via
        // TaxesProvider::get_tax_settings().
        return;
    }

    /**
     * @param $payment
     *
     * @return void
     */
    public function pms_payment_save_form( $payment = null ) {

        if ( is_null( $payment ) ) {
            return;
        }

        $fields_to_save = $this->admin_payment_billing_fields( $payment->id );

        foreach ( $fields_to_save as $key => $field ) {
            $value = isset( $_REQUEST[ $key ] ) ? $_REQUEST[ $key ] : '';
            if ( ! empty( $value ) ) {
                update_pmpro_membership_order_meta( $payment->id, $key, $value );
            }
        }

    }

    /**
     * Add extra fields to the admin payment form
     *
     * @param $fields
     *
     * @return mixed
     */
    public function tax_extra_fields( $tax_fields ) {
        return [];
    }

}
