<?php

/**
 * Plugin Name: CryptoPayment Gateway
 * Plugin URI: https://cryptopayment.network/
 * Description: CryptoPayment Gateway was built with the core values of Cryptocurrency in mind with regards to anonymity and security. The plugin seamlessly enables your store to accept Bitcoin, Bitcoin Cash, Litecoin, Dogecoin, and more, right away by simply adding your Wallet addresses.
 * Version: 1.2.2
 * Author: Granwill
 * License: GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: cryptopayment-gateway
 * Requires at least: 4.7
 * Tested up to: 6.6
 * Requires PHP: 7.0
 * Tags: cryptopayment, payment, wordpress
 */

if ( ! defined( 'ABSPATH' ) ) exit;

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
require_once plugin_dir_path(__FILE__) . 'apps/wordpress/functions.php';
if ( ! defined('CRPAY_WP') ) define('CRPAY_WP', true);
if ( ! defined('CRPAY_MAIN_URL') ) define('CRPAY_MAIN_URL', plugin_dir_url(__FILE__));
if ( ! defined('CRPAY_URL') ) define('CRPAY_URL', plugin_dir_url(__FILE__));
if ( ! defined('CRPAY_USER') ) define('CRPAY_USER', '');
if ( ! defined('CRPAY_PASSWORD') ) define('CRPAY_PASSWORD', '');

/*
 * ----------------------------------------------------------
 * # ADMIN AREA
 * ----------------------------------------------------------
 *
 * Display the administration area and the nav menu
 *
 */

function crpay_wp_set_admin_menu()
{
    $current_user = wp_get_current_user();
    if (array_intersect(['administrator'], $current_user->roles)) {
        add_menu_page('Cryptopayment', 'Cryptopayment', 'read', 'cryptopayment', 'crpay_wp_admin_action', CRPAY_URL.'media/icon-18x18.png');
    }
}

function crpay_wp_admin_action()
{
    require_once __DIR__.'/vendor/cryptd/functions.php';
    if (crpay_db_check_connection() !== true) {
        crpay_installation(crpay_wp_installation_array());
    }
    if (strpos(CRPAY_URL, site_url()) === false) {
        crpay_installation(crpay_wp_installation_array());
    }
    require __DIR__.'/vendor/cryptd/admin_code.php';
    crpay_box_admin();
}

function crpay_wp_enqueue_admin() 
{
    if (crpay_wp_is_admin_page()) {
        require_once __DIR__.'/vendor/cryptd/functions.php';
        
        // Sanitize localhost variable
        $localhost = isset($_GET['localhost']) ? sanitize_text_field(wp_unslash($_GET['localhost'])) : '';
        
        // Determine whether to minify scripts
        $min = crpay_settings_get('minify') && (empty($localhost) || !wp_verify_nonce($localhost, 'localhost')) ? '.min' : '';
        
        // Enqueue scripts
        wp_enqueue_script('cryptopayment-client', CRPAY_URL . 'js/client' . esc_js($min) . '.js', [], CRPAY_VERSION, true);
        wp_enqueue_script('crpay-admin', CRPAY_URL . 'js/admin' . esc_js($min) . '.js', [], CRPAY_VERSION, true);
        
        // Check admin verification
        if (!crpay_verify_admin()) {
            $data = [CRPAY_USER, true];
            $GLOBALS['CRPAY_LOGIN'] = $data;

            // Escape the data for inline script
            $encrypted_data = esc_js(crpay_encryption(wp_json_encode($data, JSON_INVALID_UTF8_IGNORE | JSON_UNESCAPED_UNICODE)));
            wp_add_inline_script('crpay-admin', 'CRYPTOPayment.cookie("CRPAY_LOGIN", "' . $encrypted_data . '", 365, "set");');
        }
        
        // Enqueue styles
        wp_enqueue_style('crpay-admin', CRPAY_URL . 'css/admin.css', [], CRPAY_VERSION, 'all');
        wp_enqueue_style('crpay-admin-wp', CRPAY_URL . 'apps/wordpress/admin.css', [], CRPAY_VERSION, 'all');
        // Add inline script with escaping
        wp_add_inline_script('crpay-admin', esc_js(crpay_settings_js_admin()) . 'var CRPAY_WP = true; jQuery(document).ready(function () { jQuery(".crpay-admin").css("min-height", (jQuery(window).height() - 32) + "px") });');
        
        // Enqueue shop admin script if defined
        if (defined('CRPAY_SHOP')) {
            wp_enqueue_script('crpay-admin-shop', CRPAY_URL . 'apps/shop/shop.admin.js', [], CRPAY_VERSION, true);
        }
    }
}


/*
 * ----------------------------------------------------------
 * # SHORTCODES
 * ----------------------------------------------------------
 *
 */

function crpay_wp_checkout_shortcode($attributes)
{
    extract(shortcode_atts(['id' => '', 'price' => '', 'external-reference' => '', 'redirect' => '', 'currency' => '', 'type' => ''], $attributes));
    crpay_wp_shared_shortcode_functions();

    return '<div data-cryptopayment="'.crpay_isset($attributes, 'id', '').'" data-price="'.crpay_isset($attributes, 'price', '').'" data-external-reference="'.crpay_isset($attributes, 'external-reference', '').'" data-redirect="'.crpay_isset($attributes, 'redirect', '').'" data-currency="'.crpay_isset($attributes, 'currency', '').'" data-type="'.crpay_isset($attributes, 'type', '').'"></div>';
}

function crpay_wp_payment_shortcode($attributes)
{
    remove_action('shutdown', 'wp_ob_end_flush_all', 1);
    crpay_wp_shared_shortcode_functions();
    ob_start();
    crpay_checkout_direct();
    $return = ob_get_contents();
    ob_end_clean();
    return $return;
}

function crpay_wp_shared_shortcode_functions() 
{
    // Check if 'localhost' exists in the query parameters and validate the nonce
    $is_localhost = isset($_GET['localhost']) ? wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['localhost'])), 'localhost') : false;

    // Determine the appropriate JavaScript file to load
    $script_file = crpay_settings_get('minify') && !$is_localhost ? 'js/client.min.js' : 'js/client.js';

    // Enqueue the script, ensuring the path is correctly sanitized
    wp_enqueue_script('cryptopayment', esc_url(CRPAY_URL . $script_file), ['jquery'], CRPAY_VERSION, true);

    // Add inline JavaScript if needed, with sanitization and escaping
    $inline_js = crpay_wp_client_inline_js();
    if (!empty($inline_js)) {
        wp_add_inline_script('cryptopayment', esc_js($inline_js), 'before');
    }
}

/*
 * ----------------------------------------------------------
 * # WOOCOMMERCE
 * ----------------------------------------------------------
 *
 */

if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
    function crpay_declare_cart_checkout_blocks_compatibility()
    {
        if (class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) {
            \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('cart_checkout_blocks', __FILE__, true);
        }
    }

    function crpay_wc_add_to_gateways($gateways)
    {
        $gateways[] = 'CRPAY_Cryptopayment';

        return $gateways;
    }

    function crpay_wc_plugin_links($links)
    {
        return array_merge(['<a href="'.admin_url('/admin.php?page=wc-settings&tab=checkout&section=cryptopayment').'">'.crpay_('Settings').'</a>'], $links);
    }

    function crpay_checkout_block_support()
    {
        if (class_exists('Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType') && file_exists(__DIR__.'/vendor/cryptd/config.php')) {
            final class CRPAY_Cryptopayment_Blocks extends AbstractPaymentMethodType
            {
                private $gateway;
                protected $name = 'cryptopayment';

                public function initialize()
                {
                    $this->settings = get_option('woocommerce_cryptopayment_settings', []);
                    $this->gateway = new CRPAY_Cryptopayment();
                }

                public function is_active()
                {
                    return $this->gateway->is_available();
                }

                public function get_payment_method_script_handles()
                {
                    wp_register_script('cryptopayment-blocks-integration', plugin_dir_url(__FILE__).'/apps/wordpress/checkout.js', ['wc-blocks-registry', 'wc-settings', 'wp-element', 'wp-html-entities', 'wp-i18n'], '1.0.0', true);
                    if (function_exists('wp_set_script_translations')) {
                        wp_set_script_translations('cryptopayment-blocks-integration');
                    }

                    return ['cryptopayment-blocks-integration'];
                }

                public function get_payment_method_data()
                {
                    return ['title' => $this->gateway->title, 'description' => $this->gateway->description];
                }
            }

            add_action('woocommerce_blocks_payment_method_type_registration', function (Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry) {
                $payment_method_registry->register(new CRPAY_Cryptopayment_Blocks());
            });
        }
    }

    function crpay_wc_init()
    {
        class CRPAY_Cryptopayment extends WC_Payment_Gateway
        {
            public function __construct()
            {
                require_once __DIR__.'/vendor/cryptd/functions.php';
                $this->id = 'cryptopayment';
                $this->has_fields = false;
                $this->method_title = 'Cryptopayment';
                $this->method_description = 'Accept cryptocurrency payments.';
                $this->title = crpay_(crpay_settings_get('wp-payment-option-name', 'Pay with crypto'));
                $this->description = crpay_(crpay_settings_get('wp-payment-option-text', 'Pay via Bitcoin, Ethereum and other cryptocurrencies.'));
                $this->init_form_fields();
                $this->init_settings(); // Maybe it cause payment gateway not to show up
                $icon = crpay_settings_get('wp-payment-option-icon');
                if ($icon) {
                    $this->icon = $icon;
                }
                add_action('woocommerce_update_options_payment_gateways_'.$this->id, [$this, 'process_admin_options']);
            }

            public function process_payment($order_id)
            {
                require_once __DIR__.'/vendor/cryptd/functions.php';
                $order = wc_get_order($order_id);
                $order->update_status('pending');
                wc_reduce_stock_levels($order);
                $url = crpay_wp_get_checkout_page();
                if (!crpay_settings_db('wp_api_url')) {
                    crpay_settings_db('wp_api_url', site_url().'/wp-json/cryptopayment/webhook');
                }
				$nonce = wp_create_nonce( 'crpay_error_nonce' );
                return ['result' => 'success', 'redirect' => $url ? $url.'?&checkout_id=custom-wc-'.$order_id.'&price='.$order->get_total().'&currency='.strtolower($order->get_currency()).'&external_reference='.crpay_encryption($order_id.'|'.$this->get_return_url($order).'|woo').'&plugin=woocommerce&note='.urlencode('WooCommerce order ID '.$order_id) : CRPAY_URL.'apps/wordpress/functions.php?crpay_error=url&_wpnonce='.$nonce];
            }

            public function init_form_fields()
            {
                $this->form_fields = apply_filters('crpay_offline_form_fields', ['enabled' => ['title' => __('Enable/Disable', 'cryptopayment-gateway'), 'type' => 'checkbox', 'label' => __('Enable Cryptopayment', 'cryptopayment-gateway'), 'default' => 'yes']]);
            }
        }
    }

    add_filter('woocommerce_payment_gateways', 'crpay_wc_add_to_gateways');
    add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'crpay_wc_plugin_links');
    add_action('woocommerce_blocks_loaded', 'crpay_checkout_block_support');
    add_action('plugins_loaded', 'crpay_wc_init', 11);
    add_action('before_woocommerce_init', 'crpay_declare_cart_checkout_blocks_compatibility');
}

function crpay_wp_on_load() 
{
    if (function_exists('is_checkout') && is_checkout() || (function_exists('edd_is_checkout') && edd_is_checkout())) {
        // Register and enqueue a script for the checkout page
        wp_register_script('crpay-script', false, [], CRPAY_VERSION, true);

        // Check for language cookie and add inline JavaScript for setting the CRPAY_LANGUAGE cookie
        $language = crpay_wp_language(false);
        $inline_script = '';
        if ($language || isset($_COOKIE['CRPAY_LANGUAGE'])) {
            $inline_script .= 'document.cookie = "CRPAY_LANGUAGE=' . esc_js($language) . ';expires=Thu, 01 Jan 2050 00:00:01 GMT;path=/;";';
        }

        // If on EDD checkout, add additional redirect logic
        if (function_exists('edd_is_checkout') && edd_is_checkout()) {
            $inline_script .= 'var crpay_href = document.location.href;';
            $inline_script .= 'if (crpay_href.includes("checkout_id")) {';
            $inline_script .= 'document.location = "' . esc_js(crpay_wp_get_checkout_page()) . '" + crpay_href.substring(crpay_href.indexOf("?"));';
            $inline_script .= '}';
        }

        // Add inline JavaScript and enqueue the script
        wp_add_inline_script('crpay-script', $inline_script);
        wp_enqueue_script('crpay-script');
    }
}

// Hook into WordPress to load the script at the right time
add_action('wp_enqueue_scripts', 'crpay_wp_on_load');

/*
 * ----------------------------------------------------------
 * # EASY DIGITAL DOWNLOADS
 * ----------------------------------------------------------
 *
 */

function crpay_edd_edd_register_gateway($gateways)
{
    if (file_exists(__DIR__ . '/vendor/cryptd/config.php')) {
        require_once __DIR__ . '/vendor/cryptd/functions.php';
        $gateways['cryptopayment'] = [
            'admin_label' => 'Cryptopayment',
            'checkout_label' => esc_html(crpay_(crpay_settings_get('wp-payment-option-name', 'Pay with crypto')))
        ];
    }

    return $gateways;
}

function crpay_edd_process_payment($data)
{
    if (!edd_get_errors()) {
        $payment_id = edd_insert_payment($data);
        if (!crpay_settings_db('wp_edd_url')) {
            crpay_settings_db('wp_edd_url', edd_get_success_page_uri());
        }
        if (!crpay_settings_db('wp_api_url')) {
            crpay_settings_db('wp_api_url', site_url() . '/wp-json/cryptopayment/webhook');
        }
        $url = '?checkout_id=custom-edd-' . $payment_id . '&price=' . esc_html($data['price']) . '&currency=' . strtolower(edd_get_currency()) . '&external_reference=' . crpay_encryption($payment_id . '|edd') . '&plugin=edd&note=' . urlencode('Easy Digital Downloads order ID ' . $payment_id);
        edd_send_back_to_checkout($url);
    }
}

function crpay_edd_disable_gateway_cc_form()
{
    return;
}

add_action('edd_gateway_cryptopayment', 'crpay_edd_process_payment');
add_filter('edd_payment_gateways', 'crpay_edd_edd_register_gateway');
add_action('edd_cryptopayment_cc_form', 'crpay_edd_disable_gateway_cc_form');

/*
 * ----------------------------------------------------------
 * # FUNCTIONS
 * ----------------------------------------------------------
 *
 */

function crpay_wp_get_checkout_page()
{
    $url = trim(crpay_settings_get('woocommerce-payment-page'));
    $language = crpay_wp_language();
    if ($language) {
        $post_id_translation = false;
        if (function_exists('pll_default_language')) {
            $default_language = pll_default_language();
            if ($language != $default_language) {
                $post_id = url_to_postid($url);
                if ($post_id) {
                    $post_id_translation = crpay_isset(pll_get_post_translations($post_id), $language);
                }
            }
        } elseif (defined('ICL_LANGUAGE_CODE')) {
            $default_language = apply_filters('wpml_default_language', null);
            if ($language != $default_language) {
                $post_id = url_to_postid($url);
                if ($post_id) {
                    $post_id_translation = apply_filters('wpml_object_id', $post_id, 'post', false, $language);
                }
            }
        }
        if ($post_id_translation) {
            $url = get_page_link($post_id_translation);
        }
    }

    return esc_url($url);
}

function crpay_wp_language($check_cookie = true)
{
    $language = false;
    if (!crpay_settings_get('language')) {
        $language = defined('ICL_LANGUAGE_CODE') ? ICL_LANGUAGE_CODE : get_locale();
        if ($language) {
            $language = substr($language, 0, 2);
        }
        if ($check_cookie && (!$language || $language == 'en')) {
            $language = isset( $_COOKIE['CRPAY_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['CRPAY_LANGUAGE'] ) ) : '';
        }
        if ($language == 'en') {
            $language = false;
        }
    }

    return $language;
}

function crpay_wp_client_inline_js()
{
    $language = crpay_wp_language();

    return 'var CRPAY_WP_AJAX_URL = "' . esc_url(admin_url('admin-ajax.php')) . '";' . ($language ? 'var CRPAY_LANGUAGE = "' . esc_js($language) . '"' : '');
}

function crpay_wp_is_admin_page() {
    $screen = get_current_screen();
    return isset($screen->id) && $screen->id === 'toplevel_page_cryptopayment'; 
}

function crpay_wp_on_init()
{
	$path = __DIR__ . '/vendor/cryptd/config.php';

    require_once __DIR__ . '/vendor/cryptd/functions.php';
    crpay_installation(crpay_wp_installation_array());
}

function crpay_wp_installation_array()
{
    $user = wp_get_current_user();
    $db_host = DB_HOST;
    $db_port = null;
    if (strpos($db_host, ':')) {
        $array = explode(':', $db_host);
        $db_host = $array[0];
        $db_port = $array[1];
    }

    return [
        'db-name' => DB_NAME,
        'db-user' => DB_USER,
        'db-password' => DB_PASSWORD,
        'db-host' => $db_host,
        'db-port' => $db_port,
        'url' => plugin_dir_url( __FILE__ ),
        'user' => esc_html($user->user_login),
        'password' => $user->user_pass
    ];
}

function crpay_wp_on_user_logout($user_id)
{
    if (!headers_sent()) {
        setcookie('CRPAY_LOGIN', '', time() - 3600);
    }

    return $user_id;
}

function crpay_wp_webhook_callback($request) 
{
	$jsonData = $request->get_body();

	// Basic input validation
	if (!is_string($jsonData)) {
        wp_die(esc_html(crpay_error('Invalid Json String', __FUNCTION__)));
	}
	
    // Decode JSON input
    $response = json_decode($jsonData, true);

    // Check if JSON is valid
    if (json_last_error() !== JSON_ERROR_NONE || !is_array($response)) {
        wp_die(esc_html(crpay_error('Invalid JSON input', __FUNCTION__)));
    }

    // Sanitize and validate the key
    $key = isset($response['key']) ? sanitize_text_field($response['key']) : null;
    if (!$key || ($key !== CRPAY_PASSWORD && $key !== crpay_settings_get('webhook-secret'))) {
        wp_die(esc_html(crpay_error('Invalid key', __FUNCTION__)));
    }

    // Check and sanitize the transaction data
    $transaction = isset($response['transaction']) && is_array($response['transaction']) ? $response['transaction'] : null;
    if (!$transaction) {
        wp_die(esc_html(crpay_error('Transaction not found', __FUNCTION__)));
    }

    // Process external reference
	$external_reference = isset($transaction['external_reference']) ? sanitize_text_field($transaction['external_reference']) : '';
    $external_reference = explode('|', crpay_encryption(esc_html($external_reference)));
	// Check and sanitize the transaction id
	$transaction_id = isset($transaction['id']) ? sanitize_text_field($transaction['id']) : '';
    $text = 'Cryptopayment transaction ID: ' . esc_html($transaction_id);

    if (in_array('woo', $external_reference)) {
        // WooCommerce order processing
        $order_id = absint($external_reference[0]);
        $order = wc_get_order($order_id);
        
        if (!$order) {
            wp_die(esc_html(crpay_error('Invalid WooCommerce order', __FUNCTION__)));
        }

        // Sanitize and validate transaction fields
        $amount_fiat = isset($transaction['amount_fiat']) ? floatval($transaction['amount_fiat']) : null;
        $currency = isset($transaction['currency']) ? sanitize_text_field($transaction['currency']) : null;

        // Validate order amount and currency
        if ((!crpay_settings_get('accept-underpayments') && $amount_fiat < $order->get_total()) || strtoupper($currency) !== strtoupper($order->get_currency())) {
            wp_die(esc_html(crpay_error('Invalid amount or currency', __FUNCTION__, true)));
        }

        // Handle order status
        if ($order->get_status() === 'pending') {
            $complete_order = crpay_settings_get('woocommerce-do-not-complete');
            if ($complete_order) {
                $order->update_status('processing');
            } else {
                // Check if all items are virtual/downloadable
                $is_virtual = true;
                foreach ($order->get_items() as $item) {
                    $product = wc_get_product($item->get_product_id());
                    if ($product && !$product->is_virtual() && !$product->is_downloadable()) {
                        $is_virtual = false;
                        break;
                    }
                }
                $is_virtual ? $order->payment_complete() : $order->update_status('processing');
            }
            // Add a secure order note
            $order->add_order_note(esc_html($text));
            exit('success');
        }
    } 

    // Handle any other invalid status
    wp_die(esc_html(crpay_error('Invalid order status', __FUNCTION__)));
}

/*
 * ------------------------------
 * # ACTIONS
 * ------------------------------
 *
 */

add_shortcode('crpay-cryptopayment', 'crpay_wp_checkout_shortcode');
add_shortcode('crpay-cryptopayment-pay', 'crpay_wp_payment_shortcode');
add_action('admin_menu', 'crpay_wp_set_admin_menu');
add_action('network_admin_menu', 'crpay_wp_set_admin_menu');
add_action('admin_enqueue_scripts', 'crpay_wp_enqueue_admin');
add_action('wp_logout', 'crpay_wp_on_user_logout');
add_action('init', 'crpay_wp_on_init');
add_action('wp_head', 'crpay_wp_on_load');
add_action('rest_api_init', function () {
    register_rest_route('cryptopayment', '/webhook', [
        'methods' => 'POST',
		'callback' => 'crpay_wp_webhook_callback',
        'permission_callback' => '__return_true',
        'args' => [
            'id' => [
                'validate_callback' => function ($param, $request, $key) {
                    return is_numeric($param);
                },
            ],
        ],
    ]);
});