<?php
/**
 * filtersAdmin.php
 *
 * @since      1.0.0
 * @author     alfiopiccione <alfio.piccione@gmail.com>
 * @license    http://opensource.org/licenses/gpl-2.0.php GPL v2
 *
 * Copyright (C) 2025 POP
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

use WcElectronInvoice\Providers\OrderQuery;

if (! defined('ABSPATH')) {
    exit; // Exit if accessed directly.
}

$orderProvider    = new \POPxPMPro\Providers\OrdersProvider();
$productsProvider = new \POPxPMPro\Providers\ProductsProvider();
$taxesProvider    = new \POPxPMPro\Providers\TaxesProvider();

//
//  array(
//      'filter'        => ''
//      'callback'      => ''
//      'priority'      => ''
//      'accepted_args' => ''
//  )
//
$filters = array(
    'admin' => array(
        'action' => array(

            // TODO: enrich orders list with a column containing the invoice number, ecc.

            // todo update all these hooks to match pmpro admin actions.
            // save POP order meta after the payment has been created
            /*
            array(
                'filter'        => 'pms_payment_insert',
                'callback'      => array($orderProvider, 'on_payment_insert'),
                'priority'      => 100,
                'accepted_args' => 2,
            ),

            // save some payment meta after the payment is updated (e.g. payment update from admin)
            array(
                'filter'        => 'pms_payment_update',
                'callback'      => array($orderProvider, 'on_payment_admin_edit'),
                'priority'      => 100,
                'accepted_args' => 3,
            ),
            */

            // registering the products provider for PMS
            array(
                'filter'        => 'wc_el_inv-enqueue_orders_provider',
                'callback'      => array($orderProvider, 'enqueue'),
                'priority'      => 10,
                'accepted_args' => 1,
            ),

            // registering the products provider for PMS
            array(
                'filter'        => 'wc_el_inv-enqueue_products_provider',
                'callback'      => array($productsProvider, 'enqueue'),
                'priority'      => 10,
                'accepted_args' => 1,
            ),

            // registering the taxes provider for PMS
            array(
                'filter'        => 'wc_el_inv-enqueue_taxes_provider',
                'callback'      => array($taxesProvider, 'enqueue'),
                'priority'      => 10,
                'accepted_args' => 1,
            ),

            /**
             * Allow updating the invoice number from the admin order edit screen.
             */
            array(
                'filter'   => 'pmpro_updated_order',
                'callback' => function ( \MemberOrder $order ) {
                    if ( ! is_admin() ) {
                        return;
                    }

                    $orderId = (int) ( $order->id ?? 0 );
                    if ( $orderId < 1 ) {
                        return;
                    }

                    if ( ! \POPxPMPro\Functions\Utils::acquirePmproOrderProcessingLock( $orderId, 'pmpro_order_persistence' ) ) {
                        return;
                    }

                    try {
                        // Skip cron/ajax/rest contexts entirely.
                        if ( ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() )
                             || ( defined( 'DOING_CRON' ) && DOING_CRON )
                             || ( defined( 'REST_REQUEST' ) && REST_REQUEST )
                        ) {
                            return;
                        }

                        // Bail if we are not on the PMPro single order edit/save action.
                        $requestPage  = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : '';
                        $requestNonce = isset( $_REQUEST['pmpro_orders_nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['pmpro_orders_nonce'] ) ) : '';
                        // PMPro sometimes uses `id`, sometimes `order`.
                        $requestOrderId = isset( $_REQUEST['id'] ) ? absint( wp_unslash( $_REQUEST['id'] ) ) : 0;
                        if ( ! $requestOrderId && isset( $_REQUEST['order'] ) ) {
                            $requestOrderId = absint( wp_unslash( $_REQUEST['order'] ) );
                        }
                        if ( ! $requestOrderId && isset( $_REQUEST['_wp_http_referer'] ) ) {
                            $refererQuery = wp_parse_url( wp_unslash( $_REQUEST['_wp_http_referer'] ), PHP_URL_QUERY );
                            parse_str( (string) $refererQuery, $refererParams );
                            if ( isset( $refererParams['order'] ) ) {
                                $requestOrderId = absint( $refererParams['order'] );
                            } elseif ( isset( $refererParams['id'] ) ) {
                                $requestOrderId = absint( $refererParams['id'] );
                            }
                            if ( ! $requestPage && isset( $refererParams['page'] ) ) {
                                $requestPage = sanitize_text_field( $refererParams['page'] );
                            }
                        }

                        // Nonce present but no page param? Assume pmpro-orders only if referer contains it.
                        if ( ! $requestPage && $requestNonce && ! empty( $refererParams['page'] ) && 'pmpro-orders' === $refererParams['page'] ) {
                            $requestPage = 'pmpro-orders';
                        }

                        // Fallback to screen check if page param missing.
                        if ( ! $requestPage && function_exists( 'get_current_screen' ) ) {
                            $currentScreen = get_current_screen();
                            if ( $currentScreen && false !== strpos( $currentScreen->id, 'pmpro-orders' ) ) {
                                $requestPage = 'pmpro-orders';
                            }
                        }

                        $isOrderEditPage = ( 'pmpro-orders' === $requestPage ) && $requestOrderId === (int) $order->id;
                        // PMPro switched the nonce action from `save` to `save_order`; accept both for compatibility.
                        $nonceIsValid    = $requestNonce && ( wp_verify_nonce( $requestNonce, 'save_order' ) || wp_verify_nonce( $requestNonce, 'save' ) );
                        $isSavingAction  = $nonceIsValid;

                        if ( ! $isOrderEditPage || ! $isSavingAction ) {
                            return;
                        }

                        $billing_map = [
                        'billing_firstname' => 'bfirstname',
                        'billing_lastname'  => 'blastname',
                        'billing_address1'  => 'baddress1',
                        'billing_address2'  => 'baddress2',
                        'billing_city'      => 'bcity',
                        'billing_state'     => 'bstate',
                        'billing_postcode'  => 'bzipcode',
                        'billing_country'   => 'bcountry',
                        'billing_phone'     => 'bphone',
                    ];
                        $pmpro_meta_map = [
                        'billing_firstname' => 'pmpro_bfirstname',
                        'billing_lastname'  => 'pmpro_blastname',
                        'billing_address1'  => 'pmpro_baddress1',
                        'billing_address2'  => 'pmpro_baddress2',
                        'billing_city'      => 'pmpro_bcity',
                        'billing_state'     => 'pmpro_bstate',
                        'billing_postcode'  => 'pmpro_bzipcode',
                        'billing_country'   => 'pmpro_bcountry',
                        'billing_phone'     => 'pmpro_bphone',
                    ];

                    // Optional admin action: preload order fields from user profile before save.
                        $syncAction = isset( $_POST['pop_pmpro_sync_from_user'] ) ? sanitize_key( wp_unslash( $_POST['pop_pmpro_sync_from_user'] ) ) : '';
                        if ( $syncAction && $order->user_id && in_array( $syncAction, [ 'fill_missing', 'overwrite' ], true ) ) {
                        $forceOverwrite  = ( 'overwrite' === $syncAction );
                        $syncInvoiceKeys = [ 'billing_choice_type', 'billing_invoice_type', 'billing_sdi_type', 'billing_vat_number', 'billing_company', 'billing_tax_code' ];
                        $syncMetaKeys    = $syncInvoiceKeys;

                        foreach ( $syncMetaKeys as $syncMetaKey ) {
                            $orderValue = get_pmpro_membership_order_meta( $order->id, $syncMetaKey, true );
                            $userValue  = get_user_meta( $order->user_id, $syncMetaKey, true );

                            if ( '' === (string) $userValue && isset( $pmpro_meta_map[ $syncMetaKey ] ) ) {
                                $userValue = get_user_meta( $order->user_id, $pmpro_meta_map[ $syncMetaKey ], true );
                            }

                            $userValue = is_string( $userValue ) ? trim( $userValue ) : $userValue;
                            if ( '' === (string) $userValue ) {
                                continue;
                            }

                            if ( ! $forceOverwrite && '' !== trim( (string) $orderValue ) ) {
                                continue;
                            }

                            $_POST[ $syncMetaKey ] = $userValue;
                        }
                    }

                        $hasExistingUserValue = static function ( $userId, $metaKey ) {
                        $currentValue = get_user_meta( $userId, $metaKey, true );
                        return '' !== trim( (string) $currentValue );
                        };

                    // Sync invoice/billing metas on order.
                    // Do not overwrite user meta with empty values when user already has saved data.
                        $meta_keys = [ 'billing_choice_type', 'billing_invoice_type', 'billing_sdi_type', 'billing_vat_number', 'billing_company', 'billing_tax_code' ];
                        foreach ( $meta_keys as $meta_key ) {
                        if ( array_key_exists( $meta_key, $_POST ) ) {
                            $meta_value = \WcElectronInvoice\Functions\filterInput( $_POST, $meta_key );
                            $meta_value = ( null === $meta_value ) ? '' : $meta_value;

                            update_pmpro_membership_order_meta( $order->id, $meta_key, $meta_value );

                            if ( $order->user_id ) {
                                if ( '' === trim( (string) $meta_value ) && $hasExistingUserValue( $order->user_id, $meta_key ) ) {
                                    continue;
                                }

                                update_user_meta( $order->user_id, $meta_key, $meta_value );
                            }
                        }
                    }

                    // Sync full billing data to order meta + user meta (same logic as checkout).
                        foreach ( $billing_map as $meta_key => $request_key ) {
                        $hasRequestKey = array_key_exists( $request_key, $_POST );
                        $hasMetaKey    = array_key_exists( $meta_key, $_POST );

                        // Only process when the admin explicitly sent the field (even if empty).
                        if ( ! $hasRequestKey && ! $hasMetaKey ) {
                            continue;
                        }

                        $raw_value = $hasRequestKey ? \WcElectronInvoice\Functions\filterInput( $_POST, $request_key ) : null;
                        if ( null === $raw_value && $hasMetaKey ) {
                            $raw_value = \WcElectronInvoice\Functions\filterInput( $_POST, $meta_key );
                        }

                        $meta_value = ( null === $raw_value ) ? '' : stripslashes( sanitize_text_field( $raw_value ) );

                        update_pmpro_membership_order_meta( $order->id, $meta_key, $meta_value );

                        if ( $order->user_id ) {
                            if ( '' === trim( (string) $meta_value ) && $hasExistingUserValue( $order->user_id, $meta_key ) ) {
                                continue;
                            }

                            update_user_meta( $order->user_id, $meta_key, $meta_value );

                            if ( isset( $pmpro_meta_map[ $meta_key ] ) ) {
                                if ( '' === trim( (string) $meta_value ) && $hasExistingUserValue( $order->user_id, $pmpro_meta_map[ $meta_key ] ) ) {
                                    continue;
                                }

                                update_user_meta( $order->user_id, $pmpro_meta_map[ $meta_key ], $meta_value );
                            }
                        }
                    }

                        $orderProvider = \WcElectronInvoice\Providers\OrderQuery::instance()->getProviderOrder( $order->id, 'pmpro' );
                        if ( ! ( $orderProvider instanceof POPxPMPro\Providers\Order ) ) {
                            return;
                        }

                    $newInvoiceNumber   = isset( $_POST['order_number_invoice'] ) ? sanitize_text_field( wp_unslash( $_POST['order_number_invoice'] ) ) : '';
                    $newInvoiceDate     = isset( $_POST['order_date_invoice'] ) ? sanitize_text_field( wp_unslash( $_POST['order_date_invoice'] ) ) : '';
                    $newInvoiceHours    = isset( $_POST['order_hours_invoice'] ) ? sanitize_text_field( wp_unslash( $_POST['order_hours_invoice'] ) ) : '';
                    $newInvoiceMinutes  = isset( $_POST['order_minutes_invoice'] ) ? sanitize_text_field( wp_unslash( $_POST['order_minutes_invoice'] ) ) : '';
                    $natureRc           = array_key_exists( 'nature_rc', $_POST ) ? sanitize_text_field( wp_unslash( $_POST['nature_rc'] ) ) : null;
                    $refNormRc          = array_key_exists( 'ref_norm_rc', $_POST ) ? sanitize_text_field( wp_unslash( $_POST['ref_norm_rc'] ) ) : null;
                    if ( ! \WcElectronInvoice\WooCommerce\Fields\ReverseChargeSettings::supportsNormativeReference() ) {
                        $refNormRc = '';
                    }
                    $dateFieldsProvided = array_key_exists( 'order_date_invoice', $_POST ) || array_key_exists( 'order_hours_invoice', $_POST ) || array_key_exists( 'order_minutes_invoice', $_POST );
                    $shouldRepairTaxes  = function () use ( $order, $orderProvider ) {
                        if ( 'success' !== (string) $order->status ) {
                            return false;
                        }

                        if ( ! get_option( 'pop_pmpro_enable_tax_calculation' ) ) {
                            return false;
                        }

                        if ( 'sent' === $orderProvider->get_invoice_sent() ) {
                            return false;
                        }

                        $total    = round( (float) ( $order->total ?? 0 ), 2 );
                        $subtotal = round( (float) ( $order->subtotal ?? 0 ), 2 );
                        $tax      = round( (float) ( $order->tax ?? 0 ), 2 );

                        if ( $total <= 0 ) {
                            return false;
                        }

                        $totalsMismatch = abs( ( $subtotal + $tax ) - $total ) > 0.01;

                        $businessCountry = function_exists( 'pop_pmproGetBusinessAddressCountry' ) ? pop_pmproGetBusinessAddressCountry() : '';
                        if ( '' === (string) $businessCountry ) {
                            return $totalsMismatch;
                        }

                        $vatNumber = get_pmpro_membership_order_meta( $order->id, 'billing_vat_number', true );
                        $customerCountry = get_pmpro_membership_order_meta( $order->id, 'billing_country', true );
                        if ( empty( $customerCountry ) && ! empty( $order->billing_country ) ) {
                            $customerCountry = $order->billing_country;
                        }
                        if ( empty( $customerCountry ) && isset( $order->billing->country ) ) {
                            $customerCountry = $order->billing->country;
                        }
                        if ( empty( $customerCountry ) && ! empty( $order->user_id ) ) {
                            $customerCountry = get_user_meta( $order->user_id, 'pmpro_bcountry', true );
                        }
                        if ( empty( $customerCountry ) && ! empty( $order->user_id ) ) {
                            $customerCountry = get_user_meta( $order->user_id, 'billing_country', true );
                        }

                        $expectedTaxRate = function_exists( 'pop_getTaxRateForCustomer' )
                            ? (float) pop_getTaxRateForCustomer( $businessCountry, $customerCountry, $vatNumber )
                            : 0.0;
                        $taxMissing = $expectedTaxRate > 0 && $tax <= 0;

                        return $totalsMismatch || $taxMissing;
                    };

                        if ( $shouldRepairTaxes() ) {
                            \POPxPMPro\Functions\Utils::pmProAdjustRenewalTaxes( $order );
                        }

                        if ( '' !== $newInvoiceNumber ) {
                            $numerationType = $orderProvider->get_billing_choice_type() ?: 'invoice';
                            $orderProvider->update_meta( 'order_number_invoice', $newInvoiceNumber );
                            \WcElectronInvoice\Functions\setFormattedInvoiceNumber( $orderProvider, $numerationType );
                        }

                        if ( null !== $natureRc ) {
                            $orderProvider->update_meta( 'nature_rc', $natureRc );
                        }

                        if ( null !== $refNormRc ) {
                            $orderProvider->update_meta( 'ref_norm_rc', $refNormRc );
                        }

                        if ( '' !== $newInvoiceDate && '' !== $newInvoiceHours && '' !== $newInvoiceMinutes ) {
                            $hours      = max( 0, min( 23, (int) $newInvoiceHours ) );
                            $minutes    = max( 0, min( 59, (int) $newInvoiceMinutes ) );
                            $dateString = sprintf( '%s %02d:%02d', $newInvoiceDate, $hours, $minutes );

                            try {
                                $date = new \DateTime( $dateString );
                                $orderProvider->update_meta( 'order_date_invoice', $date->format( 'Y-m-d H:i:s' ) );
                            } catch ( \Exception $e ) {
                                // Ignore invalid date formats.
                            }
                        } elseif ( $dateFieldsProvided && '' === $newInvoiceDate ) {
                            $orderProvider->delete_meta( 'order_date_invoice' );
                        }

                        \WcElectronInvoice\Functions\clearCachedDocumentAttachmentCache( $orderProvider, true );
                    } finally {
                        \POPxPMPro\Functions\Utils::releasePmproOrderProcessingLock( $orderId, 'pmpro_order_persistence' );
                    }
                },
                'priority' => 90,
            ),
        ),
        'filter' => array(
            // format number for refund
            // @todo verificare che sia tutto ok.
            array(
                'filter'        => 'wc_el_inv-normalize_formatted_number',
                'callback'      => function ($formattedNumber, $orderProvider) {
                    if ($orderProvider instanceof \POPxPMPro\Providers\Order && $orderProvider->get_status() === 'refunded') {
                        $formattedNumber = $orderProvider->get_meta("{$orderProvider->get_type()}_formatted_number_{$orderProvider->get_id()}");
                    }

                    return $formattedNumber;
                },
                'priority'      => 10,
                'accepted_args' => 2,
            ),

            /**
             * Filter number for connected invoice
             */
            array(
                'filter' => 'wc_el_inv-invoice_connected_number',
                'callback' => function($number, $order) {
                    return \POPxPMPro\Functions\Utils::pmProConnectedInvoiceNumber($order);
                },
                'priority' => 10,
                'accepted_args' => 2,
            ),

            /**
             * Filter unit price and total price when stamp duty and rivalsa is applied
             */
            array(
                'filter'        => array('wc_el_inv-shop_item_unit_price', 'wc_el_inv-shop_item_total_price'),
                'callback'      => function($amount, $orderID, $provider) {
                    return \POPxPMPro\Functions\Utils::pmProGetNetSubscriptionAmount($amount, $orderID, $provider);
                },
                'priority'      => 10,
                'accepted_args' => 3,
            ),
        ),
    ),
);

add_filter('wc_el_inv-filters_admin', function ($filtersAdmin) use ($filters) {

    $filtersAdmin['admin']['action'] = array_merge($filtersAdmin['admin']['action'], $filters['admin']['action']);
    $filtersAdmin['admin']['filter'] = array_merge($filtersAdmin['admin']['filter'], $filters['admin']['filter']);

    return $filtersAdmin;
}, 10, 1);

return $filters;
