<?php
/**
 * Api.php
 *
 * @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.
 */

namespace WooPoPToFattureAruba\Functions;

use WcElectronInvoice\Admin\Settings\OptionPage;
use WcElectronInvoice\Xml\CreateXml;
use WooPoPToFattureAruba\Api;
use WooPoPToFattureAruba\Jobs;
use WooPoPToFattureAruba\TimeZone;
use function WcElectronInvoice\Functions\getXmlFromOrder;
use function WcElectronInvoice\Functions\isXml;
use function WcElectronInvoice\Functions\plainTextFromHtml;

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

/**
 * getDateTime
 *
 * @return string
 */
function getDateTime()
{
    return date_i18n('d/m/Y H:i');
}

/**
 * Reset login data
 * Used for debug
 *
 * @param $delete
 *
 * @return void
 */
function resetApi($delete = false)
{
    $reset = filterInput($_GET, 'waf_reset_login', FILTER_VALIDATE_INT);
    if (intval($reset) === 1 || $delete) {
        // Delete API data
        delete_option('waf_store_login');
        delete_option('waf_access_token');
        delete_option('waf_refresh_token');

        if (intval($reset) === 1) {
            wp_redirect(admin_url('admin.php?page=wc_el_inv-options-page&tab=addon'));
            die();
        }
    }
}

/**
 * Get Active api data
 *
 * @return object
 */
function getActiveApi()
{
    $loginStored = get_option('waf_store_login');
    // base url oAuth
    $apiOauthUrl = OAUTH_URL . '/';
    // base url WebService
    $apiWsUrl          = WS_URL . '/';
    $apiUid            = get_option('waf_api_uid');
    $apiKey            = get_option('waf_api_key');
    $accessToken       = get_option('waf_access_token');
    $refreshToken      = get_option('waf_refresh_token');
    $expireAccessToken = get_option('waf_access_token_expires_in') ?: null;

    return (object)array(
        'active'            => $loginStored,
        'apiOauthUrl'       => $apiOauthUrl,
        'apiWsUrl'          => $apiWsUrl,
        'apiUid'            => $apiUid,
        'apiKey'            => $apiKey,
        'accessToken'       => $accessToken,
        'refreshToken'      => $refreshToken,
        'expireAccessToken' => (int)$expireAccessToken + (MINUTE_IN_SECONDS * 30),
    );
}

/**
 * Set access token, refresh and expires_in
 *
 * @param $data
 *
 * @return void
 */
function updateTokenData($data)
{
    // Store access_token and refresh_token
    update_option('waf_access_token', "{$data->access_token}");
    update_option('waf_refresh_token', "{$data->refresh_token}");

    $timeZone = new TimeZone();
    $timeZone = new \DateTimeZone($timeZone->getTimeZone()->getName());
    $time     = new \DateTime('now');
    $time->setTimezone($timeZone);

    update_option(
        'waf_access_token_expires_in',
        $time->getTimestamp()
    );
}

/**
 * Aruba oAuth SignIn
 *
 * @see https://fatturazioneelettronica.aruba.it/apidoc/docs.html#auth-signin
 *
 * @param bool $background
 *
 * @return bool|void
 */
function authSignIn($background = false)
{
    // No ajax request ?
    if (! isAjaxRequest()) {
        return;
    }

    $apiUid = filterInput($_POST, 'apiUid', FILTER_UNSAFE_RAW);
    $apiKey = filterInput($_POST, 'apiKey', FILTER_UNSAFE_RAW);
    $nonce  = filterInput($_POST, 'nonce', FILTER_UNSAFE_RAW);

    if (! wp_verify_nonce($nonce, 'waf_scripts-ajax_nonce')) {
        return;
    }

    if (! $apiUid || ! $apiKey) {
        $response = array(
            'message' => esc_html__('OAuth Request error: Invalid params', WP_FATT_ARUBA_TEXTDOMAIN),
            'code'    => 501,
        );

        wp_send_json($response);
        die();
    }

    // Store login check
    update_option('waf_store_login', true);
    update_option('waf_api_uid', "{$apiUid}");
    update_option('waf_api_key', "{$apiKey}");

    try {
        $baseUri = getActiveApi()->apiOauthUrl;
        $uri     = $baseUri . \WooPoPToFattureAruba\Api::$routes['login'];

        // Client
        $client = new \GuzzleHttp\Client(['base_uri' => $uri]);
        // Request authorization_code
        $response = $client->post($uri, [
            \GuzzleHttp\RequestOptions::FORM_PARAMS => [
                'grant_type' => 'password',
                'username'   => $apiUid,
                'password'   => $apiKey,
            ],
        ]);

        $data = json_decode($response->getBody());

        if ($data && $data->token_type === 'bearer') {
            // Store access_token and refresh_token
            updateTokenData($data);

            // Access Token response
            $responseToken = array(
                'body'          => $data,
                'message'       => __('Access Token successful!', WP_FATT_ARUBA_TEXTDOMAIN),
                'requestURI'    => $uri,
                'access_token'  => $data->access_token,
                'refresh_token' => $data->refresh_token,
                'code'          => 200,
            );

            // Slack notify
            \WooPoPToFattureAruba\Functions\slack(
                WP_FATT_ARUBA_NAME . __(' oAuth SignIn Response : ', WP_FATT_ARUBA_TEXTDOMAIN) .
                "\n" . $responseToken['message'] .
                "\n" . "Access Token: " . $responseToken['access_token'],
                false,
                ':information_source:',
                "\n\n" . "Data:" . "\n" . print_r($responseToken, true),
            );

            if (! $background) {
                wp_send_json($responseToken);
                die();
            } else {
                return true;
            }
        } else {
            $responseArgs = array(
                'message' => esc_html__('Invalid OAuth request', WP_FATT_ARUBA_TEXTDOMAIN),
                'data'    => $data,
                'code'    => 501,
            );

            // Slack notify
            \WooPoPToFattureAruba\Functions\slack(
                WP_FATT_ARUBA_NAME . __(' oAuth SignIn Response : ',
                    WP_FATT_ARUBA_TEXTDOMAIN) . "\n" . print_r($responseArgs, true),
                false,
                ':information_source:'
            );

            if (! $background) {
                wp_send_json($responseArgs);
                die();
            } else {
                return false;
            }
        }
    } catch (\Exception $e) {
        if (400 === $e->getCode()) {
            $dataException = array(
                'message'   => esc_html__('Error, The token is expired.', WP_FATT_ARUBA_TEXTDOMAIN),
                'e-message' => $e->getMessage(),
                'e-trace'   => $e->getTraceAsString(),
                'code'      => 400,
            );

            \WooPoPToFattureAruba\Functions\log($dataException);

            resetApi(true);
            wp_send_json($dataException);
            die();
        }

        $traceString = '';
        if ('dev' === WP_FATT_ARUBA) {
            $traceString = ' Trace: ' . $e->getTraceAsString();
        }

        $dataException = array(
            'message' => esc_html('Exception Message: ' . $e->getMessage() . $traceString),
            'code'    => $e->getCode(),
        );

        \WooPoPToFattureAruba\Functions\log($dataException);

        wp_send_json($dataException);
        die();
    }
}

/**
 * Force - Aruba oAuth SignIn
 *
 * (*) Force SignIn if expire access token
 *
 * @param bool $background
 *
 * @return bool|void
 */
function forceSignIn($background = false)
{
    if ((int)getActiveApi()->expireAccessToken < time()) {
        $_POST = [
            'apiUid' => getActiveApi()->apiUid,
            'apiKey' => getActiveApi()->apiKey,
            'nonce'  => wp_create_nonce('waf_scripts-ajax_nonce'),
        ];

        return authSignIn($background);
    }

    return true;
}

/**
 * Refreshing access token
 *
 * @see https://fatturazioneelettronica.aruba.it/apidoc/docs.html#auth-refresh
 *
 * @param bool $background
 *
 * @return bool|void
 */
function refreshOAuthToken($background = false)
{
    if ((int)getActiveApi()->expireAccessToken < time()) {
        // Force Aruba auth SignIn
        return forceSignIn($background);
    } else {
        try {
            $baseUri = getActiveApi()->apiOauthUrl;
            $uri     = $baseUri . \WooPoPToFattureAruba\Api::$routes['login'];

            // Client
            $client = new \GuzzleHttp\Client(['base_uri' => $uri]);
            // Request refresh_token
            $response = $client->post($uri, [
                \GuzzleHttp\RequestOptions::FORM_PARAMS => [
                    'grant_type'    => 'refresh_token',
                    'refresh_token' => getActiveApi()->refreshToken,
                ],
            ]);

            $refreshData = json_decode($response->getBody());
            if ($refreshData && $refreshData->token_type === 'bearer') {

                // Store access_token and refresh_token
                updateTokenData($refreshData);

                // Refreshing response
                $responseToken = array(
                    'body'          => $refreshData,
                    'message'       => __('Refreshing Access Token successful!', WP_FATT_ARUBA_TEXTDOMAIN),
                    'requestURI'    => $uri,
                    'access_token'  => $refreshData->access_token,
                    'refresh_token' => $refreshData->refresh_token,
                    'code'          => 200,
                );

                // Slack notify
                \WooPoPToFattureAruba\Functions\slack(
                    WP_FATT_ARUBA_NAME . __(' Refreshing token request : ',
                        WP_FATT_ARUBA_TEXTDOMAIN) .
                    "\n" . $responseToken['message'] .
                    "\n" . "Access Token: " . $responseToken['access_token'],
                    false,
                    ':information_source:',
                    "\n\n" . "Data:" . "\n" . print_r($responseToken, true),
                );

                if (! $background) {
                    wp_send_json($responseToken);
                    die();
                } else {
                    return true;
                }
            } else {
                $responseArgs = array(
                    'message' => esc_html__('Invalid Refreshing token request', WP_FATT_ARUBA_TEXTDOMAIN),
                    'code'    => 501,
                );

                // Slack notify
                \WooPoPToFattureAruba\Functions\slack(
                    WP_FATT_ARUBA_NAME . __(' Refreshing token request : ',
                        WP_FATT_ARUBA_TEXTDOMAIN) . "\n" . print_r($responseArgs, true),
                    false,
                    ':information_source:'
                );

                if (! $background) {
                    wp_send_json($responseArgs);
                    die();
                } else {
                    return false;
                }
            }
        } catch (\Exception $e) {
            $traceString = '';
            if ('dev' === WP_FATT_ARUBA) {
                $traceString = ' Trace: ' . $e->getTraceAsString();
            }

            $dataException = array(
                'message' => esc_html('Exception Message: ' . $e->getMessage() . $traceString),
                'code'    => $e->getCode(),
            );

            wp_send_json($dataException);
            die();
        }
    }
}

/**
 * Upload Invoice
 *
 * @see https://fatturazioneelettronica.aruba.it/apidoc/docs.html#services-invoice-upload
 *
 * @return object|void
 * @throws \Exception
 */
function uploadInvoice()
{
    $key = OptionPage::getK();
    if(! $key) {
        \WooPoPToFattureAruba\Functions\log("POP secret-api-key undefined" . "\n");
        wp_send_json(array(
            'title'   => __('Oops, something is wrong!', WP_FATT_ARUBA_TEXTDOMAIN),
            'body'    => null,
            'message' => esc_html__('Warning: the POP license expired', WP_FATT_ARUBA_TEXTDOMAIN),
            'code'    => 501,
        ));
        return;
    }

    // No ajax request ?
    if (! isAjaxRequest()) {
        return;
    }

    $nonce          = filterInput($_POST, 'nonce', FILTER_UNSAFE_RAW);
    $choiceType     = filterInput($_POST, 'choiceType', FILTER_UNSAFE_RAW);
    $orderID        = filterInput($_POST, 'orderID', FILTER_UNSAFE_RAW);
    $provider       = filterInput($_POST, 'provider', FILTER_UNSAFE_RAW);
    $ajaxAction     = filterInput($_POST, 'ajaxAction', FILTER_UNSAFE_RAW);
    $jobForceSignIn = filterInput($_POST, 'jobForceSignIn', FILTER_UNSAFE_RAW);

    if (! wp_verify_nonce($nonce, 'waf_scripts-ajax_nonce')) {
        return;
    }

    // Return if invoice is sent
    $scheduledCronJob = get_option('waf_scheduled_events');
    $checkSent        = \WcElectronInvoice\Functions\getPostMeta('_invoice_sent', null, $orderID, true, 'order', $provider);
    if ('on' === $scheduledCronJob &&
        \WcElectronInvoice\Functions\isBackgroundExecutionMode($ajaxAction, ['feCronJobUploadRequest']) &&
        'sent' === $checkSent
    ) {
        return;
    }

    $apiData = getActiveApi();
    $order   = \WcElectronInvoice\Providers\OrderQuery::instance()->getProviderOrder($orderID, $provider);

    // auto refreshOAuthToken
    if (\WcElectronInvoice\Functions\shouldRespondWithImmediateError($ajaxAction, ['feCronJobUploadRequest']) &&
        (! $apiData->expireAccessToken || (int)$apiData->expireAccessToken < time())
    ) {
        refreshOAuthToken(true);
    }

    $wcOrderClass       = \WcElectronInvoice\Functions\wcOrderClassName($order, '\WC_Order');
    $wcOrderRefundClass = \WcElectronInvoice\Functions\wcOrderClassName($order, '\WC_Order_Refund');

    if ($apiData->accessToken &&
        ((is_subclass_of($order, '\WcElectronInvoice\Providers\Order') ||
          is_subclass_of($order, '\WcElectronInvoice\Providers\OrderRefund')) ||
         ($order instanceof $wcOrderClass ||
          $order instanceof $wcOrderRefundClass))
    ) {

        // Get POP XML
        $key = get_option('wc_el_inv-secret-api-key');
        // Order ID
        $orderID = $order->get_id();

        // Normalize type for XML (no XML format for receipt)
        if ('receipt' === $choiceType) {
            $choiceType = 'invoice';
        }

        $xml             = false;
        $isXmlFromRemoTe = false;
        $validXML        = false;
        if (\WcElectronInvoice\Functions\shouldRespondWithImmediateError($ajaxAction,
                ['feCronJobUploadRequest'])) {
            $url = esc_url_raw(add_query_arg([
                CreateXml::LIST_TYPE => $orderID,
                'provider'           => $provider,
                'key'                => $key,
                'format'             => 'xml',
                'choice_type'        => $choiceType,
                'addon'              => 'fatturearuba',
                'v'                  => time(),
            ], site_url('/' . \WcElectronInvoice\EndPoint\Endpoints::ENDPOINT)));
            $xml = wp_remote_get($url, \WcElectronInvoice\Functions\getSessionCookieArgs('application/xml'));
            $xml = wp_remote_retrieve_body($xml);

            // Is valid XML ?
            $isXmlFromRemoTe = isXml($xml);
            $validXML        = $isXmlFromRemoTe->valid;
        }

        // Fallback for get XML
        if ((is_object($isXmlFromRemoTe) && ! $validXML) || ! $isXmlFromRemoTe) {
            // Get xml from order
            $xml = getXmlFromOrder($order);
        }

        // Is valid XML ?
        $isXml = isXml($xml);
        $overquotaPayload = \WcElectronInvoice\Functions\extractPopApiOverquotaUiPayload($xml);

        // Not valid ?
        if (! $isXml->valid) {
            if (is_array($overquotaPayload)) {
                wp_send_json($overquotaPayload, (int)($overquotaPayload['status'] ?? 500));
                die();
            }

            $uploadError = \WcElectronInvoice\Functions\mapUploadPreconditionError('aruba', 'xml_invalid');
            $noXmlResponse = array(
                'title'   => __('Oops, something is wrong!', WP_FATT_ARUBA_TEXTDOMAIN),
                'errors'  => $isXml->errors,
                'xml'     => $isXml->xml,
                'message' => __('Request error: xml not valid', WP_FATT_ARUBA_TEXTDOMAIN),
                'code'    => $uploadError['code'],
            );

            // Send error email
            $emailBody = __('Oops, something is wrong!', WP_FATT_ARUBA_TEXTDOMAIN) . "\n" .
                         __('Order: ', WP_FATT_ARUBA_TEXTDOMAIN) . '#' . $orderID . "\n" .
                         __('The invoice could not be created, we recommend that you check your order data and try again',
                             WP_FATT_ARUBA_TEXTDOMAIN) . "\n" .
                         __('Message:', WP_FATT_ARUBA_TEXTDOMAIN) . "\n" . $noXmlResponse['message'] .
                         __('Errors:', WP_FATT_ARUBA_TEXTDOMAIN) . "\n" . print_r($noXmlResponse['errors'], true);
            sendEmailToAdminForInvoiceCreateError($emailBody, $orderID);

            // Log
            \WooPoPToFattureAruba\Functions\log(print_r($noXmlResponse, true));

            wp_send_json($noXmlResponse);
            die();
        }

        $lockKey = \WcElectronInvoice\Functions\buildDbLockKey('aruba', 'upload_invoice', (int)$orderID,
            (string)$provider, (string)$choiceType);
        $lockDecision = \WcElectronInvoice\Functions\evaluateLockBusyDecision(
            \WcElectronInvoice\Functions\acquireDbLock($lockKey, 0),
            \WcElectronInvoice\Functions\isBackgroundExecutionMode($ajaxAction, ['feCronJobUploadRequest'])
        );
        if (! $lockDecision['continue']) {
            if ($lockDecision['respond_error']) {
                $lockError = \WcElectronInvoice\Functions\mapLockBusyError('aruba', 'upload_invoice');
                wp_send_json(array(
                    'message' => __('Action skipped: another upload process is already running for this order.',
                        WP_FATT_ARUBA_TEXTDOMAIN),
                    'orderID' => $orderID,
                    'code'    => $lockError['code'],
                ));
                die();
            }

            return;
        }

        try {
            // XML in Base64
            $xmlB64 = base64_encode($xml);

            $body = \WcElectronInvoice\Functions\buildArubaUploadPayload($xmlB64);

            $baseUri = getActiveApi()->apiWsUrl;
            $uri     = $baseUri . \WooPoPToFattureAruba\Api::$routes['upload'];

            // Client
            $client  = new \GuzzleHttp\Client(['base_uri' => $uri]);
            $headers = [
                'Authorization' => 'Bearer ' . getActiveApi()->accessToken,
                'Accept'        => 'application/json',
                'Content-Type'  => 'application/json;charset=UTF-8',
            ];
            // Upload Request
            $response     = $client->request('post', $uri, [
                \GuzzleHttp\RequestOptions::HEADERS => $headers,
                \GuzzleHttp\RequestOptions::BODY    => json_encode($body),
            ]);
            $responseData = json_decode($response->getBody());

            if (property_exists($responseData, 'uploadFileName') && 200 === $response->getStatusCode()) {
                // Synchronous Controls
                // @see https://fatturazioneelettronica.aruba.it/apidoc/docs.html#synchronous-checks
                if ("0000" !== $responseData->errorCode ||
                    ! \WcElectronInvoice\Functions\canMarkInvoiceSentWithUploadFileName($responseData->uploadFileName)
                ) {
                    $uploadError = \WcElectronInvoice\Functions\mapUploadPreconditionError('aruba', 'upload_failed');
                    $responseArgs = array(
                        'body'           => $responseData,
                        'message'        => ! empty($responseData->errorDescription) ? $responseData->errorDescription : __('Invoice upload error!',
                            WP_FATT_ARUBA_TEXTDOMAIN),
                        'orderID'        => $orderID,
                        'jobForceSignIn' => $jobForceSignIn,
                        'requestURI'     => $uri,
                        'code'           => $uploadError['code'],
                    );
                } else {
                    $order->update_meta('waf-upload_file_name', $responseData->uploadFileName);
                    if (\WcElectronInvoice\Functions\canMarkInvoiceSentWithUploadFileName($responseData->uploadFileName)) {
                        $order->update_meta('_invoice_sent', 'sent');
                    }
                    // Save
                    $order->save();
                    $responseArgs = array(
                        'body'           => $responseData,
                        'message'        => sprintf('%s:%s - %s',
                            __('Invoice', WP_FATT_ARUBA_TEXTDOMAIN),
                            $responseData->uploadFileName,
                            __('Invoice uploaded successfully!', WP_FATT_ARUBA_TEXTDOMAIN)
                        ),
                        'orderID'        => $orderID,
                        'jobForceSignIn' => $jobForceSignIn,
                        'requestURI'     => $uri,
                        'code'           => $response->getStatusCode(),
                    );
                }
            } else {
                $uploadError = \WcElectronInvoice\Functions\mapUploadPreconditionError('aruba', 'upload_failed');
                $responseArgs = array(
                    'body'           => $responseData,
                    'message'        => __('Invoice upload error!', WP_FATT_ARUBA_TEXTDOMAIN),
                    'orderID'        => $orderID,
                    'jobForceSignIn' => $jobForceSignIn,
                    'requestURI'     => $uri,
                    'code'           => $uploadError['code'],
                );
            }

            /**
             * Hook upload invoice
             */
            do_action('waf-upload_invoice',
                $ajaxAction,
                $orderID,
                $response->getStatusCode(),
                property_exists($responseData, 'uploadFileName') ? $responseData->uploadFileName : null,
                property_exists($responseData, 'errorDescription') ? $responseData->errorDescription : null
            );

            // Slack notify
            \WooPoPToFattureAruba\Functions\slack(
                WP_FATT_ARUBA_NAME . ' ' . $responseArgs['message'],
                false,
                ':information_source:',
                "\n\n" . "Data:" . "\n" . print_r($responseArgs, true),
            );

            // Log
            \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($responseArgs,
                    true));

            // Cron Job return data
            if ('on' === $scheduledCronJob &&
                \WcElectronInvoice\Functions\isBackgroundExecutionMode($ajaxAction, ['feCronJobUploadRequest']) &&
                'sent' !== $checkSent
            ) {
                \WcElectronInvoice\Functions\releaseDbLock($lockKey);
                return (object)array(
                    'fileName' => property_exists($responseData, 'uploadFileName') ? $responseData->uploadFileName : null,
                    'status'   => $responseArgs['code'],
                );
            }

            \WcElectronInvoice\Functions\releaseDbLock($lockKey);
            wp_send_json($responseArgs);
            die();
        } catch (\Exception $e) {
            if (401 === $e->getCode()) {
                $dataException = array(
                    'message'   => esc_html__('Unauthorized: the Token seems to be invalid, update it!',
                        WP_FATT_ARUBA_TEXTDOMAIN),
                    'e-message' => $e->getMessage(),
                    'e-trace'   => $e->getTraceAsString(),
                    'code'      => $e->getCode(),
                );
            } else {
                $dataException = array(
                    'message'   => esc_html('Exception Upload invoice: ' . $e->getMessage()),
                    'e-message' => $e->getMessage(),
                    'e-trace'   => $e->getTraceAsString(),
                    'code'      => $e->getCode(),
                );
            }

            // Send error email
            $emailBody = __('Oops, something is wrong!', WP_FATT_ARUBA_TEXTDOMAIN) . "\n" .
                         __('Order: ', WP_FATT_ARUBA_TEXTDOMAIN) . '#' . $orderID . "\n" .
                         __('The invoice could not be created, we recommend that you check your order data and try again',
                             WP_FATT_ARUBA_TEXTDOMAIN) . "\n" .
                         __('Message:', WP_FATT_ARUBA_TEXTDOMAIN) . "\n" . $dataException['message'] .
                         __('Errors:', WP_FATT_ARUBA_TEXTDOMAIN) . "\n" . $e->getTraceAsString();
            sendEmailToAdminForInvoiceCreateError($emailBody, $orderID);

            // Log
            \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($dataException,
                    true));

            \WcElectronInvoice\Functions\releaseDbLock($lockKey);
            wp_send_json($dataException);
            die();
        }
    }

    $responseArgs = array(
        'body'    => null,
        'message' => __('uploadInvoice request error', WP_FATT_ARUBA_TEXTDOMAIN),
        'code'    => 501,
    );

    // Log
    \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($responseArgs, true));

    wp_send_json($responseArgs);
    die();
}

/**
 * Get Document State
 *
 * @see https://fatturazioneelettronica.aruba.it/apidoc/docs.html#services-invoice-out-getByFilename
 *
 * @return void
 * @throws \Exception
 */
function getDocumentState()
{
    // No ajax request ?
    if (! isAjaxRequest()) {
        return;
    }

    $nonce               = filterInput($_POST, 'nonce', FILTER_UNSAFE_RAW);
    $docName             = filterInput($_POST, 'docName', FILTER_UNSAFE_RAW);
    $orderID             = filterInput($_POST, 'orderID', FILTER_UNSAFE_RAW);
    $provider            = filterInput($_POST, 'provider', FILTER_UNSAFE_RAW);
    $ajaxAction          = filterInput($_POST, 'ajaxAction', FILTER_UNSAFE_RAW);
    $includePdfFile      = boolval(filterInput($_POST, 'includePdfFile', FILTER_UNSAFE_RAW));
    $includePdfFileParam = $includePdfFile ? 'true' : 'false';

    if (! wp_verify_nonce($nonce, 'waf_scripts-ajax_nonce')) {
        return;
    }

    // auto refreshOAuthToken
    $apiData = getActiveApi();
    if (! $ajaxAction && ! $apiData->expireAccessToken || (int)$apiData->expireAccessToken < time()) {
        refreshOAuthToken(true);
    }

    try {
        $baseUri = getActiveApi()->apiWsUrl;
        $uri     = $baseUri . \WooPoPToFattureAruba\Api::$routes['get_invoice'];

        // Client
        $client   = new \GuzzleHttp\Client(['base_uri' => $uri]);
        $headers  = [
            'Authorization' => 'Bearer ' . getActiveApi()->accessToken,
            'Accept'        => 'application/json',
        ];
        $response = $client->request('get',
            $uri . "?filename={$docName}&includePdf={$includePdfFileParam}&includeFile=false", [
                \GuzzleHttp\RequestOptions::HEADERS => $headers,
            ]);

        $responseData = json_decode($response->getBody());
        $infoState    = __('Nessun stato trovato', WP_FATT_ARUBA_TEXTDOMAIN);

        if (null !== $responseData->id && 200 === $response->getStatusCode()) {
            if (! empty($responseData->invoices)) {
                $infoState = sprintf('%s %s - "%s"', __('Fattura: ', WP_FATT_ARUBA_TEXTDOMAIN),
                    $responseData->invoices[0]->number, $responseData->invoices[0]->status);
            }

            $responseArgs = array(
                'body'         => $responseData,
                'message'      => __('State request', WP_FATT_ARUBA_TEXTDOMAIN),
                'messageState' => $infoState,
                'orderID'      => $orderID,
                'requestURI'   => $uri,
                'code'         => $response->getStatusCode(),
            );
        } else {
            $responseArgs = array(
                'body'       => $responseData,
                'message'    => __('State request error', WP_FATT_ARUBA_TEXTDOMAIN),
                'orderID'    => $orderID,
                'requestURI' => $uri,
                'code'       => $response->getStatusCode(),
            );
        }

        /**
         * WooCommerce > Email_Customer_Invoice
         * Send the email with the invoice attached
         */
        if ($includePdfFile && $responseData->pdfFile && 'woocommerce' === $provider) {
            $pdfFile = base64_decode($responseData->pdfFile);
            if (! class_exists('WC_Email_Customer_Invoice')) {
                $WC   = \WooCommerce::instance();
                $path = $WC->plugin_path();
                require_once $path . '/includes/emails/class-wc-email.php';
                require_once $path . '/includes/emails/class-wc-email-customer-invoice.php';
            }

            if (class_exists('WC_Email_Customer_Invoice')) {
                // Set attachments
                add_filter('woocommerce_email_attachments',
                    function ($attachments, $emailID, $order, $wcEmail) use ($pdfFile, $responseData) {
                        $pdfPath = \WooPoPToFattureAruba\Plugin::getPluginDirPath('/tempPdf/invoice.pdf');
                        file_put_contents($pdfPath, $pdfFile);
                        if ($pdfPath) {
                            $attachments[] = \WooPoPToFattureAruba\Plugin::getPluginDirPath('/tempPdf') . '/invoice.pdf';
                        }

                        return $attachments;
                    }, PHP_INT_MAX, 4);

                // WC order
                $order = wc_get_order($orderID);

                if ($order instanceof \WC_Order) {
                    // Init WC Customer Invoice Email
                    $invoiceEmail         = new \WC_Email_Customer_Invoice();
                    $invoiceEmail->object = $order;
                    $invoiceEmail->trigger($order->get_id(), $order);
                    $order->update_meta_data('waf-sending_proforma', true);
                    unset($responseData->pdfFile);
                    $responseArgs['emailSending'] = 1;
                    $responseArgs['message']      = __('Sent PDF Pro Forma', WP_FATT_ARUBA_TEXTDOMAIN);
                    $responseArgs['invoiceLink']  = \WooPoPToFattureAruba\Plugin::getPluginDirUrl('/tempPdf') . '/invoice.pdf';
                } else {
                    $order->update_meta_data('waf-sending_proforma', false);
                    $responseArgs['emailSending'] = 0;
                    $responseArgs['message']      = __('Error Sending PDF Pro Forma - Order null',
                        WP_FATT_ARUBA_TEXTDOMAIN);
                    $responseArgs['invoiceLink']  = null;
                }

                // Save
                $order->save();
            }
        }

        // Slack notify
        \WooPoPToFattureAruba\Functions\slack(
            WP_FATT_ARUBA_NAME . ' ' . $responseArgs['message'] . ' - Doc: ' . $docName . "\n" . $infoState,
            false,
            ':information_source:',
            "\n\n" . "Data:" . "\n" . print_r($responseArgs, true),
        );

        // Log
        \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($responseArgs,
                true));

        wp_send_json($responseArgs);
        die();
    } catch (\Exception $e) {
        if (401 === $e->getCode()) {
            $dataException = array(
                'message'   => esc_html__('Unauthorized: the Token seems to be invalid, update it!',
                    WP_FATT_ARUBA_TEXTDOMAIN),
                'e-message' => $e->getMessage(),
                'e-trace'   => $e->getTraceAsString(),
                'code'      => $e->getCode(),
            );
        } else {
            $dataException = array(
                'message'   => esc_html('State request: ' . $e->getMessage()),
                'e-message' => $e->getMessage(),
                'e-trace'   => $e->getTraceAsString(),
                'code'      => $e->getCode(),
            );
        }

        // Log
        \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($dataException,
                true));

        wp_send_json($dataException);
        die();
    }
}

/**
 * Get Document Notify
 *
 * @see  https://fatturazioneelettronica.aruba.it/apidoc/docs.html#_getbyinvoicefilename
 *
 * @return void
 * @throws \Exception
 */
function getDocumentNotify()
{
    // No ajax request ?
    if (! isAjaxRequest()) {
        return;
    }

    $ajaxAction = filterInput($_POST, 'ajaxAction', FILTER_UNSAFE_RAW);

    // auto refreshOAuthToken
    $apiData = getActiveApi();
    if (! $ajaxAction && ! $apiData->expireAccessToken || (int)$apiData->expireAccessToken < time()) {
        refreshOAuthToken(true);
    }

    $nonce    = filterInput($_POST, 'nonce', FILTER_UNSAFE_RAW);
    $docName  = filterInput($_POST, 'docName', FILTER_UNSAFE_RAW);
    $orderID  = filterInput($_POST, 'orderID', FILTER_UNSAFE_RAW);
    $provider = filterInput($_POST, 'provider', FILTER_UNSAFE_RAW);

    // Get Order
    $order              = \WcElectronInvoice\Providers\OrderQuery::instance()->getProviderOrder($orderID, $provider);
    $wcOrderClass       = \WcElectronInvoice\Functions\wcOrderClassName($order, '\WC_Order');
    $wcOrderRefundClass = \WcElectronInvoice\Functions\wcOrderClassName($order, '\WC_Order_Refund');

    if (! is_subclass_of($order, '\WcElectronInvoice\Providers\Order') &&
        ! is_subclass_of($order, '\WcElectronInvoice\Providers\OrderRefund') &&
        ! $order instanceof $wcOrderClass &&
        ! $order instanceof $wcOrderRefundClass
    ) {
        return;
    }

    $invoiceType = $order->get_invoice_type();
    $sdiType     = $order->get_sdi_type();

    if (! wp_verify_nonce($nonce, 'waf_scripts-ajax_nonce')) {
        return;
    }

    try {
        $baseUri = getActiveApi()->apiWsUrl;
        $uri     = $baseUri . \WooPoPToFattureAruba\Api::$routes['get_notification_invoice'];

        // Client
        $client  = new \GuzzleHttp\Client(['base_uri' => $uri]);
        $headers = [
            'Authorization' => 'Bearer ' . getActiveApi()->accessToken,
            'Accept'        => 'application/json',
        ];

        $response = $client->request('get', $uri . "?invoiceFilename=" . $docName, [
            \GuzzleHttp\RequestOptions::HEADERS => $headers,
        ]);

        $responseData = json_decode($response->getBody());

        $newScheduledMessage  = '';
        $notificationMessages = array();
        $sendScheduled        = false;
        if (property_exists($responseData, 'notifications')) {
            if (! empty($responseData->notifications)) {
                foreach ($responseData->notifications as $notification) {
                    $type = $notification->docType;

                    // Send Proforma PDF
                    if (! $sendScheduled) {
                        // State RC condition
                        $isStateRC      = $type === 'RC';
                        // Private and state MC condition
                        $isPrivateMC    = ($type === 'MC' && $invoiceType === 'private');
                        // State RC/MC condition
                        $isStateRCorMC  = in_array($type, ['RC', 'MC'], true);

                        // Pec or sdi type 0000000 condition and state (RC/MC) condition
                        $isSdiPecEmail  = (
                            $sdiType === '0000000' ||
                            preg_match(\WooPoPToFattureAruba\Api::$regexPEC, $sdiType) ||
                            preg_match(\WooPoPToFattureAruba\Api::$regexLEGALMAIL, $sdiType) ||
                            filter_var($sdiType, FILTER_VALIDATE_EMAIL) !== false
                        );

                        // Filter for always allowed proforma
                        $alwaysAllowed  = apply_filters(
                            'waf_always_scheduled_proforma',
                            false,
                            $order,
                            $responseData->notifications
                        );

                        if (
                            $isStateRC ||
                            $isPrivateMC ||
                            ($isStateRCorMC && $isSdiPecEmail) ||
                            $alwaysAllowed
                        ) {
                            $nextScheduled = wp_next_scheduled(
                                'WooPoPToFattureArubaJobsScheduledSendProformaInvoicePdf',
                                [$order->get_id(), $docName, $provider]
                            );

                            if (! $nextScheduled) {
                                Jobs::scheduled(
                                    'WooPoPToFattureArubaJobsScheduledSendProformaInvoicePdf',
                                    [$order->get_id(), $docName, $provider],
                                    Jobs::jobTiming('email')
                                );
                                $sendScheduled = true;
                            }
                        }
                    }

                    if (null !== $notification->result && 'NE' === $type) {
                        $type = $notification->docType . '_' . $notification->result;
                    }

                    $notificationMessages[$type] = array(
                        'date'    => $notification->date,
                        'message' => __(Api::$notificationMessage[$type], WP_FATT_ARUBA_TEXTDOMAIN),
                    );

                    /**
                     * Re-Scheduled notification request
                     */
                    if ('feCronJobDocumentNotifyRequest' === $ajaxAction) {
                        if ('NS' === $type ||
                            'MC' === $type ||
                            'AT' === $type ||
                            'RC' === $type ||
                            'MT' === $type ||
                            'DT' === $type ||
                            'NE_EC01' === $type ||
                            'NE_EC02' === $type
                        ) {
                            if (property_exists($notification, 'fileName')) {
                                $time          = Jobs::jobTiming('notify');
                                $nextScheduled = wp_next_scheduled(
                                    'WooPoPToFattureArubaJobsScheduledNotify',
                                    [$order->get_id(), $notification->fileName, $provider]
                                );
                                if (! $nextScheduled) {
                                    $newScheduledMessage = __('New schedule for the notification set',
                                        WP_FATT_ARUBA_TEXTDOMAIN);
                                    Jobs::scheduled(
                                        'WooPoPToFattureArubaJobsScheduledNotify',
                                        [$order->get_id(), $notification->fileName, $provider],
                                        $time
                                    );
                                }
                            }
                        }
                    }
                }

                if (! empty($notificationMessages)) {
                    $order->update_meta('waf-notifications', $notificationMessages);
                }
            } else {

                // Filter for always allowed proforma
                if (true === apply_filters('waf_always_scheduled_proforma', false, $order, array())) {
                    $nextScheduled = wp_next_scheduled(
                        'WooPoPToFattureArubaJobsScheduledSendProformaInvoicePdf',
                        [$order->get_id(), $docName, $provider]
                    );
                    if (! $nextScheduled) {
                        Jobs::scheduled(
                            'WooPoPToFattureArubaJobsScheduledSendProformaInvoicePdf',
                            [$order->get_id(), $docName, $provider],
                            Jobs::jobTiming('email')
                        );
                    }
                }

                /**
                 * Re-Scheduled notification request
                 */
                if ($docName) {
                    $time          = Jobs::jobTiming('notify');
                    $nextScheduled = wp_next_scheduled(
                        'WooPoPToFattureArubaJobsScheduledNotify',
                        [$order->get_id(), $docName, $provider]
                    );
                    if (! $nextScheduled) {
                        $newScheduledMessage = __('New schedule for the notification set', WP_FATT_ARUBA_TEXTDOMAIN);
                        Jobs::scheduled(
                            'WooPoPToFattureArubaJobsScheduledNotify',
                            [$order->get_id(), $docName, $provider],
                            $time
                        );
                    }
                }
            }
        }

        $notificationMessagesText = '';
        if (! empty($notificationMessages)) {
            foreach ($notificationMessages as $notificationMessage) {
                $notificationMessagesText .= $notificationMessage['date'] . "\n" . plainTextFromHtml($notificationMessage['message'], true) . "\n";
            }
        } else {
            $timeZone = new TimeZone();
            $timeZone = new \DateTimeZone($timeZone->getTimeZone()->getName());
            $dateTime = new \DateTime('now');
            $dateTime->setTimezone($timeZone);
            $notificationMessagesText = __('No notifications found', WP_FATT_ARUBA_TEXTDOMAIN);
            if ('' !== $newScheduledMessage) {
                $notificationMessagesText = $notificationMessagesText . '<br>' . $newScheduledMessage;
            }
            $notificationMessages['NAN'] = array(
                'date'    => $dateTime->format('d-m-Y H:i'),
                'message' => $notificationMessagesText,
            );
            $order->update_meta('waf-notifications', $notificationMessages);
        }

        // Save
        $order->save();

        if (200 === $response->getStatusCode()) {
            $responseArgs = array(
                'body'                 => $responseData,
                'message'              => __('Notifications request', WP_FATT_ARUBA_TEXTDOMAIN),
                'notificationMessages' => $notificationMessages,
                'orderID'              => $orderID,
                'requestURI'           => $uri,
                'code'                 => $response->getStatusCode(),
            );
        } else {
            $responseArgs = array(
                'body'       => $responseData,
                'message'    => __('Notifications request error', WP_FATT_ARUBA_TEXTDOMAIN),
                'orderID'    => $orderID,
                'requestURI' => $uri,
                'code'       => $response->getStatusCode(),
            );
        }

        /**
         * Hook notifications invoice
         */
        do_action('waf-notifications_invoice',
            $ajaxAction,
            $orderID,
            $uri,
            $headers,
            $docName,
            $response->getStatusCode(),
            $responseData->notifications,
        );

        // Slack notify
        \WooPoPToFattureAruba\Functions\slack(
            WP_FATT_ARUBA_NAME . ' ' . $responseArgs['message'] . ' - Doc: ' . $docName . "\n\n" . $notificationMessagesText,
            false,
            ':information_source:',
            "\n\n" . "Data:" . print_r($responseData, true),
        );

        // Log
        \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($responseArgs,
                true));

        wp_send_json($responseArgs);
        die();
    } catch (\Exception $e) {
        if (401 === $e->getCode()) {
            $dataException = array(
                'message'   => esc_html__('Unauthorized: the Token seems to be invalid, update it!',
                    WP_FATT_ARUBA_TEXTDOMAIN),
                'e-message' => $e->getMessage(),
                'e-trace'   => $e->getTraceAsString(),
                'code'      => $e->getCode(),
            );
        } else {
            $dataException = array(
                'message'   => esc_html('Notifications request: ' . $e->getMessage()),
                'e-message' => $e->getMessage(),
                'e-trace'   => $e->getTraceAsString(),
                'code'      => $e->getCode(),
            );
        }

        // Log
        \WooPoPToFattureAruba\Functions\log(WP_FATT_ARUBA_NAME . ' ' . print_r($dataException,
                true));

        wp_send_json($dataException);
        die();
    }
}
