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

namespace WooPoPToFattureAruba\Functions;

use WooPoPToFattureAruba\Plugin;

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

/**
 * Is WooCommerce active
 *
 * @return bool If the function WC exists.
 * @since 1.0.0
 *
 */
function isWooCommerceActive()
{
    return function_exists('WC');
}

/**
 * Filter Input
 *
 * @param array  $data    The haystack of the elements.
 * @param string $key     The key of the element within the haystack to filter.
 * @param int    $filter  The filter to use.
 * @param array  $options The option for the filter var.
 *
 * @return bool|mixed The value filtered on success false if filter fails or key doesn't exists.
 * @uses  filter_var() To filter the value.
 *
 * @since 1.0.0
 *
 */
function filterInput($data, $key, $filter = FILTER_DEFAULT, $options = array())
{
    // Support for PHP >= 8.1
    // 513 = FILTER_UNSAFE_RAW
    if ((phpversion() >= 8.1) && $filter === 513) {
        $filter = FILTER_UNSAFE_RAW;
    }

    return isset($data[$key]) ? filter_var($data[$key], $filter, $options) : false;
}

/**
 * Filter Input Array
 *
 * @param array  $data An array with string keys containing the data to filter.
 * @param array  $args An array defining the arguments. A valid key is a string
 *                     containing a variable name and a valid value is either a
 *                     filter type, or an
 *                     array optionally specifying the filter, flags and options.
 *                     If the value is an array, valid keys are filter
 *                     which specifies the filter type,
 *                     flags which specifies any flags that apply to the
 *                     filter, and options which specifies any options that
 *                     apply to the filter. See the example below for a better understanding.
 * @param string $key  The key of the element within the haystack to filter.
 *
 * @return bool|mixed
 */
function filterInputArray($data, $args, $key)
{
    return isset($data[$key]) ? filter_var_array($data, $args) : false;
}

/**
 * Is Ajax Request
 *
 * Define that this is a request made via ajax.
 * It's not the traditional WordPress ajax request, infact the DOING_AJAX is not set.
 * It's a convention that the argument passed with the ajaxAction query are made by an ajax request.
 *
 * @return bool
 * @since 1.0.0
 *
 */
function isAjaxRequest()
{
    // @codingStandardsIgnoreLine
    $action = filterInput($_POST, 'ajaxAction', FILTER_UNSAFE_RAW);

    // No ajax request ?
    if (empty($_POST) && ! (bool)$action &&
        ! defined('DOING_AJAX') ||
        (defined('DOING_AJAX') && ! DOING_AJAX)
    ) {
        return false;
    }

    return true;
}

/**
 * Is Associative Array
 *
 * @param array $array The array to know if is associative or not.
 *
 * @return bool         True if array is associative, false otherwise.
 * @since  1.0.0
 *
 */
function isArrayAssoc(array $array)
{
    return array_keys($array) !== range(0, count($array) - 1);
}

/**
 * Implode Assoc
 *
 * Implode an associative array
 *
 * @param string $glue    The string to use for separate the elements value.
 * @param string $assGlue The string to use to separate key and value.
 * @param array  $arr     The array to implode.
 *
 * @return string|bool The array imploded. False if $arr is not an array. False if $arr is not associative.
 * @since 1.0.0
 *
 */
function implodeAssoc($glue, $assGlue, $arr)
{
    if (wp_is_numeric_array($arr)) {
        return false;
    }

    // The string.
    $string = '';

    foreach ($arr as $k => $v) {
        if (! $v) {
            continue;
        }

        $string .= $k . $assGlue . $v . $glue;
    }

    // Remove the latest glue string.
    $string = rtrim($string, $glue);

    return $string;
}

/**
 * Insert an element into array in a specific position
 *
 * @param array $needle    The array to insert in.
 * @param array $haystack  The array to insert on.
 * @param mixed $pos       The key or index where the array should be inserted.
 * @param bool  $preserve  If the original value and positions should be preserved.
 * @param bool  $recursive To merge recursively or not the result array.
 *
 * @return array            The new merged array
 * @since  1.0.0
 *
 */
function arrayInsertInPos($needle, array &$haystack, $pos, $preserve = false, $recursive = false)
{
    $keys = array_filter(array_intersect(array_keys($needle), array_keys($haystack)), 'is_string');

    if (is_array($pos)) {
        list($key, $before) = $pos;
        $before = (isset($before) && true === $before) ? true : false;
        $pos    = array_search($key, array_keys($haystack), true);
        $pos    = $before ? $pos : $pos + 1;
    }

    if ($keys) {
        if ($preserve) {
            $arr =& $needle;
        } else {
            $arr =& $haystack;
        }

        foreach ($keys as $k => $v) {
            unset($arr[$v]);
        }
    }

    $start    = array_splice($haystack, 0, (int)$pos);
    $func     = $recursive ? 'array_merge_recursive' : 'array_merge';
    $haystack = call_user_func_array($func, array($start, (array)$needle, $haystack));

    return $haystack;
}

/**
 * Helper for get Wc Order class name
 *
 * @param $obj
 * @param $classname
 *
 * @return string
 *
 */
function wcOrderClassName($obj, $classname)
{
    if (isWooCommerceActive() && \WC()->version >= '4.0.1') {
        if ('\WC_Order' === $classname) {
            if ($obj instanceof \WC_Order) {
                return '\WC_Order';
            } elseif ($obj instanceof \Automattic\WooCommerce\Admin\Overrides\Order) {
                return '\Automattic\WooCommerce\Admin\Overrides\Order';
            }
        } elseif ('\WC_Order_Refund' === $classname) {
            if ($obj instanceof \WC_Order_Refund) {
                return '\WC_Order_Refund';
            } elseif ($obj instanceof \Automattic\WooCommerce\Admin\Overrides\OrderRefund) {
                return '\Automattic\WooCommerce\Admin\Overrides\OrderRefund';
            }
        } else {
            return $classname;
        }
    }

    return $classname;
}

/**
 * getLogConfig
 *
 * @return array
 */
function getLogConfig()
{
    $capability = property_exists(Plugin::class, 'capability') ? Plugin::$capability : 'manage_options';

    return array(
        'key'          => 'waf',
        'enabled'      => defined('WP_FATT_ARUBA_LOG') && WP_FATT_ARUBA_LOG,
        'plugin_name'  => WP_FATT_ARUBA_NAME,
        'capability'   => $capability,
        'log_dir_slug' => 'pop-to-aruba-log',
    );
}

/**
 * Check
 */
function addonOptions()
{
    $page = filterInput($_GET, 'page', FILTER_UNSAFE_RAW);
    $tab  = filterInput($_GET, 'tab', FILTER_UNSAFE_RAW);

    if ('wc_el_inv-options-page' === $page && 'addon' === $tab) {
        add_action('wc_el_inv-before_closing_settings_form', function () {
            if (! current_user_can(Plugin::$capability)) {
                echo sprintf('<p style="color:red">%s</p>',
                    esc_html__('POP Addon: You do not have the permissions to manage the add-on', WP_FATT_ARUBA_TEXTDOMAIN)
                );

                return;
            }

            $out = '';
            $out .= '<!-- addon-header --><div class="addon-header">';
            $out .= sprintf('<h2>%s - v:%s</h2>',
                __('POP Addon: Fatture Aruba', WP_FATT_ARUBA_TEXTDOMAIN),
                WP_FATT_ARUBA_VERSION
            );
            $out .= '</div><!--/ addon-header -->';
            $out .= '<!-- addon --><div class="addon">';

            $out .= '<!-- info --><div class="info">';
            $out .= sprintf('<h4>%s</h4>',
                __('Automations:', WP_FATT_ARUBA_TEXTDOMAIN));

            $valueOrderStatus       = get_option('waf_scheduled_order_status', 'completed');
            $valueCronJob           = get_option('waf_scheduled_events');
            $valueCronJobTwiceDaily = get_option('waf_scheduled_twicedaily_events');
            $sendErrorsEmail        = get_option('waf_error_sending_invoice');

            $valueCronUploadJobTime        = get_option('waf_scheduled_events_time') ?: 12;
            $valueCronNotificationsJobTime = get_option('waf_scheduled_notifications_events_time') ?: 12;
            $valueCronJob                  = 'on' === $valueCronJob ? 'checked="checked"' : '';
            $valueCronJobTwiceDaily        = 'on' === $valueCronJobTwiceDaily ? 'checked="checked"' : '';
            $sendErrorsEmail               = 'on' === $sendErrorsEmail ? 'checked="checked"' : '';

            $out .= '<input type="hidden" name="waf_options" value="1">';

            // ----------------------------------------------------- //
            // Order status for cron job
            $statuses = apply_filters('waf-cron_job_statuses', [
                'completed'  => __('Completed', WP_FATT_ARUBA_TEXTDOMAIN),
                'processing' => __('Processing', WP_FATT_ARUBA_TEXTDOMAIN),
            ]);
            $selectedValue = $valueOrderStatus ?? "completed";
            $out .= '<p><label for="wc_el_inv-settings-waf_scheduled_order_status">'.
                    __('Enable auto-send for status:', WP_FATT_ARUBA_TEXTDOMAIN) .
                    '<select id="wc_el_inv-settings-waf_scheduled_order_status" name="wc_el_inv_options[wc_el_inv-settings-waf_scheduled_order_status]">';
            foreach ($statuses as $slug => $label) {
                $selected_attr = selected($slug, $selectedValue, false);
                $out           .= '<option value="' . esc_attr($slug) . '" ' . $selected_attr . '>' . esc_html($label) . '</option>';
            }
            $out .= '</select></label></p>';
            // ----------------------------------------------------- //

            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_scheduled_events">' .
                            '<input id="wc_el_inv-settings-waf_scheduled_events" type="checkbox" name="wc_el_inv_options[wc_el_inv-settings-waf_scheduled_events]" value="on" %s>' .
                            '%s </label></p>', $valueCronJob,
                __('Enable automatic sending', WP_FATT_ARUBA_TEXTDOMAIN));

            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_scheduled_twicedaily_events">' .
                            '<input id="wc_el_inv-settings-waf_scheduled_twicedaily_events" type="checkbox" name="wc_el_inv_options[wc_el_inv-settings-waf_scheduled_twicedaily_events]" value="on" %s>' .
                            '%s </label></p>', $valueCronJobTwiceDaily,
                __('Enable automatic sending of invoices for completed orders not sent in the last 7 days. (work 2 times a day)',
                    WP_FATT_ARUBA_TEXTDOMAIN));

            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_scheduled_events_time"> %s<br>' .
                            '<input id="wc_el_inv-settings-waf_scheduled_events_time" type="number" name="wc_el_inv_options[wc_el_inv-settings-waf_scheduled_events_time]" value="%s">' .
                            '</label></p>',
                __('Time in hours for automatic sending of the invoice', WP_FATT_ARUBA_TEXTDOMAIN),
                $valueCronUploadJobTime
            );

            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_scheduled_notifications_events_time"> %s<br>' .
                            '<input id="wc_el_inv-settings-waf_scheduled_notifications_events_time" type="number" name="wc_el_inv_options[wc_el_inv-settings-waf_scheduled_notifications_events_time]" value="%s">' .
                            '</label></p>',
                __('Time in hours for automatic sending of the notifications request', WP_FATT_ARUBA_TEXTDOMAIN),
                $valueCronNotificationsJobTime
            );

            $out .= '</div><!--/ info -->';
            $out .= '<!-- info --><div class="info">';

            // Email
            $out .= sprintf('<h4>%s</h4>',
                __('Email:', WP_FATT_ARUBA_TEXTDOMAIN));
            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_error_sending_invoice">' .
                            '<input id="wc_el_inv-settings-waf_error_sending_invoice" type="checkbox" name="wc_el_inv_options[wc_el_inv-settings-waf_error_sending_invoice]" value="on" %s>' .
                            '%s <b>(%s)</b> %s</label></p>',
                $sendErrorsEmail,
                __('Send an email to the WordPress installation administrator', WP_FATT_ARUBA_TEXTDOMAIN),
                get_bloginfo('admin_email'),
                __('to report the failure to create the document on Aruba', WP_FATT_ARUBA_TEXTDOMAIN)
            );

            $out .= '</div><!--/ info -->';
            $out .= '<!-- info --><div class="info">';

            if (WP_FATT_ARUBA_LOG) {
                $logConfig = getLogConfig();
                $logStatus = \WcElectronInvoice\Functions\prepareDiagnosticLog($logConfig, true);
                $out     .= sprintf('<h4>%s: <span style="color:#46b450">%s</span></h4>',
                    __('Event log ', WP_FATT_ARUBA_TEXTDOMAIN),
                    __('Activated', WP_FATT_ARUBA_TEXTDOMAIN)
                );

                $out .= sprintf('<p><code style="word-break: break-all;">%s</code></p>',
                    esc_html($logStatus['file_path'])
                );

                if (! empty($logStatus['error'])) {
                    $out .= sprintf('<p><small style="color:#b32d2e">%s</small></p>',
                        esc_html($logStatus['error'])
                    );
                }

                if ($logStatus['ready']) {
                    $out     .= sprintf('<p><a target="_blank" class="log-link" href="%s"><span class="dashicons dashicons-text-page"></span> %s</a><hr></p>',
                        esc_url(\WcElectronInvoice\Functions\getDiagnosticLogViewerUrl($logConfig['key'])),
                        __('View the event log ', WP_FATT_ARUBA_TEXTDOMAIN)
                    );
                }
            } else {
                $out .= sprintf('<h4>%s:</h4>',
                    __('Event log ', WP_FATT_ARUBA_TEXTDOMAIN));
                $out .= sprintf('<p><code style="word-break: break-all;">define("WP_FATT_ARUBA_LOG", true);</code></p>');
                $out .= sprintf('<p><small>%s</small></p>',
                    __('Enter this code in wp-config.php to activate the event log.', WP_FATT_ARUBA_TEXTDOMAIN)
                );
                $out .= '<hr>';
            }

            $valueCheck   = get_option('waf_slack_integration');
            $valueToken   = get_option('waf_slack_integration_token');
            $valueChannel = get_option('waf_slack_integration_channel');
            $valueCheck   = 'on' === $valueCheck ? 'checked="checked"' : '';

            $out .= sprintf("<h4>%s</h4>", __('Slack configuration:', WP_FATT_ARUBA_TEXTDOMAIN));
            $out .= sprintf("<p>%s<br><strong>%s</strong><br></p>",
                __('Create Slack APP and set OAuth & Permissions Scopes', WP_FATT_ARUBA_TEXTDOMAIN),
                __('Required scopes: chat:write - chat:write.customize - incoming-webhook', WP_FATT_ARUBA_TEXTDOMAIN)
            );

            $out .= sprintf('<p><input type="hidden" name="waf_options" value="1"><label for="wc_el_inv-settings-waf_slack_integration">' .
                            '<input id="wc_el_inv-settings-waf_slack_integration" type="checkbox" name="wc_el_inv_options[wc_el_inv-settings-waf_slack_integration]" value="on" %s>' .
                            '%s </label></p>', $valueCheck,
                __('Enable slack integration notify', WP_FATT_ARUBA_TEXTDOMAIN));

            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_slack_integration_token">%s<br>' .
                            '<input id="wc_el_inv-settings-waf_slack_integration_token" type="text" name="wc_el_inv_options[wc_el_inv-settings-waf_slack_integration_token]" value="%s">' .
                            '</label></p>', __('Slack API Token', WP_FATT_ARUBA_TEXTDOMAIN), $valueToken);

            $out .= sprintf('<p><label for="wc_el_inv-settings-waf_slack_integration_channel">%s<br>' .
                            '<input id="wc_el_inv-settings-waf_slack_integration_channel" type="text" name="wc_el_inv_options[wc_el_inv-settings-waf_slack_integration_channel]" value="%s">' .
                            '</label></p>', __('Slack Channel', WP_FATT_ARUBA_TEXTDOMAIN), $valueChannel);

            $out .= '</div><!--/ info -->';
            $out .= '</div><!--/ addon -->';

            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            echo $out;
        }, 50);
    }
}

/**
 * Log
 *
 * @param $message
 */
function log($message)
{
    if (\WcElectronInvoice\Functions\writeDiagnosticLog($message, getLogConfig())) {
        \WooPoPToFattureAruba\Functions\slack("DEBUG: " . trim($message));
    }
}


/**
 * Slack notify
 *
 * Slack configuration:
 * Create Slack APP
 *
 * - OAuth & Permissions - Scopes
 *
 * 1. chat:write
 * 2. chat:write.customize
 * 3. incoming-webhook
 *
 * Use: \POPToFattureAruba\Functions\slack('message ....', 'channel_name');
 *
 * @param string $message      The message
 * @param string $slackChannel The Slack channel (debug is a developer channel)
 * @param string $emoji        The emoji
 * @param        $debugMessage
 *
 * @return bool|string
 */
function slack($message, $slackChannel = 'debug', $emoji = ':robot_face:', $debugMessage = '')
{
    $active  = get_option('waf_slack_integration');
    $token   = get_option('waf_slack_integration_token');
    $channel = get_option('waf_slack_integration_channel') ?? $slackChannel;

    if ('dev' === WP_FATT_ARUBA) {
        $message = $message . "\n\n------------\n" . "Debug" . "\n------------\n" . $debugMessage;
    }

    if ($slackChannel) {
        $channel = $slackChannel;
    }
    $siteUrl = site_url('/');

    if ('on' === $active && '' !== $token) {
        $ch   = curl_init("https://slack.com/api/chat.postMessage");
        $data = http_build_query([
            "username"   => WP_FATT_ARUBA_NAME . " Bot",
            "token"      => $token,
            // "#mychannel" channel ID,
            "channel"    => $channel,
            "text"       => $emoji . " WebSite: {$siteUrl} - " . date_i18n('d/m/Y H:i') . "\n" . $message,
            // :robot_face: - :warning: - :no_entry_sign: - :dart: - :boom: - :white_check_mark:
            "icon_emoji" => ":robot_face:",
        ]);

        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
    }

    return false;
}

/**
 * getPaymentMethodNameByCode
 *
 * @param $code
 *
 * @return mixed|void
 */
function getPaymentMethodNameByCode($code)
{
    $method = array(
        'MP01' => esc_html__('Contanti', WP_FATT_ARUBA_TEXTDOMAIN),
        'MP02' => esc_html__('Assegno', WP_FATT_ARUBA_TEXTDOMAIN),
        'MP03' => esc_html__('Assegno circolare', WP_FATT_ARUBA_TEXTDOMAIN),
        'MP05' => esc_html__('Bonifico', WP_FATT_ARUBA_TEXTDOMAIN),
        'MP08' => esc_html__('Carta di pagamento', WP_FATT_ARUBA_TEXTDOMAIN),
    );

    return $method[$code] ?: apply_filters('waf-payment_method',
        esc_html__('Bonifico', WP_FATT_ARUBA_TEXTDOMAIN)
    );
}

/**
 * getPaymentMethodCodeByMethod
 *
 * @param $method
 *
 * @return string
 */
function getPaymentMethodCodeByMethod($method)
{
    switch ($method) {
        case 'bacs':
            $code = 'MP05';
            break;
        case 'cheque':
            $code = 'MP02';
            break;
        case 'paypal':
        case 'ppec_paypal':
        case 'ppcp-gateway':
        case 'woocommerce_payments':
        case 'stripe':
        case 'xpay':
        case 'soisy':
        case 'igfs':
            $code = 'MP08';
            break;
        case 'stripe_sepa':
            $code = 'MP19';
            break;
        default:
            $code = 'MP01';
            break;
    }

    return apply_filters('waf-payment_method_code', $code, $method);
}

/**
 * getDocType
 *
 * @param $orderType
 *
 * @return string
 */
function getDocType($orderType)
{
    switch ($orderType) {
        case 'shop_order':
            $documentType = 'invoice';
            break;
        case 'shop_order_refund':
            $documentType = 'credit_note';
            break;
        default:
            $documentType = 'invoice';
            break;
    }

    return $documentType;
}

/**
 * Get key
 *
 * @param $string
 *
 * @return array|string|string[]|null
 */
function getKey($string)
{
    return preg_replace('/\s+/', '', strtolower($string));
}

/**
 * sendEmailToAdminForInvoiceCreateError
 *
 * @param $emailBody
 * @param $orderID
 *
 * @return void
 */
function sendEmailToAdminForInvoiceCreateError($emailBody, $orderID)
{
    $sendErrorsEmail = get_option('waf_error_sending_invoice');
    $adminEmail      = get_bloginfo('admin_email');
    if ('on' === $sendErrorsEmail && function_exists('wp_mail')) {
        wp_mail($adminEmail,
            sprintf(__('Error creating invoice for order: #%s', WP_FATT_ARUBA_TEXTDOMAIN), $orderID),
            $emailBody
        );
    }
}
