<?php

/**
 * The Googlepay module.
 *
 * @package WooCommerce\PayPalCommerce\Googlepay
 */
declare (strict_types=1);
namespace WooCommerce\PayPalCommerce\Googlepay;

use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
use WC_Payment_Gateway;
use WooCommerce\PayPalCommerce\ApiClient\Factory\ExperienceContextBuilder;
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
use WooCommerce\PayPalCommerce\Button\Helper\Context;
use WooCommerce\PayPalCommerce\Googlepay\Endpoint\UpdatePaymentDataEndpoint;
use WooCommerce\PayPalCommerce\Googlepay\Helper\GoogleProductStatus;
use WooCommerce\PayPalCommerce\Googlepay\Helper\AvailabilityNotice;
use WooCommerce\PayPalCommerce\Settings\Data\Definition\FeaturesDefinition;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\Settings\Data\SettingsProvider;
use WooCommerce\PayPalCommerce\Settings\DTO\LocationStylingDTO;
use WooCommerce\PayPalCommerce\Googlepay\Helper\PropertiesDictionary;
/**
 * Class GooglepayModule
 */
class GooglepayModule implements ServiceModule, ExecutableModule
{
    use ModuleClassNameIdTrait;
    /**
     * {@inheritDoc}
     */
    public function services(): array
    {
        return require __DIR__ . '/../services.php';
    }
    /**
     * {@inheritDoc}
     */
    public function run(ContainerInterface $c): bool
    {
        // Clears product status when appropriate.
        add_action('woocommerce_paypal_payments_clear_apm_product_status', static function () use ($c): void {
            $apm_status = $c->get('googlepay.helpers.apm-product-status');
            assert($apm_status instanceof GoogleProductStatus);
            $apm_status->clear();
        });
        add_action('init', static function () use ($c) {
            // Check if the module is applicable, correct country, currency, ... etc.
            if (!$c->get('googlepay.eligible')) {
                return;
            }
            // Load the button handler.
            $button = $c->get('googlepay.button');
            assert($button instanceof ButtonInterface);
            // Show notice if there are product availability issues.
            $availability_notice = $c->get('googlepay.availability_notice');
            assert($availability_notice instanceof AvailabilityNotice);
            $availability_notice->execute();
            // Check if this merchant can activate / use the buttons.
            // We allow non referral merchants as they can potentially still use GooglePay, we just have no way of checking the capability.
            if (!$c->get('googlepay.available') && $c->get('googlepay.is_referral')) {
                return;
            }
            // Initializes button rendering.
            add_action('wp', static function () use ($button) {
                if (is_admin()) {
                    return;
                }
                $button->render();
            });
            // Enqueue frontend scripts.
            add_action('wp_enqueue_scripts', static function () use ($c, $button) {
                $smart_button = $c->get('button.smart-button');
                assert($smart_button instanceof SmartButtonInterface);
                if ($smart_button->should_load_ppcp_script()) {
                    $button->enqueue();
                    return;
                }
                /*
                 * Checkout page, but no PPCP scripts were loaded. Most likely in continuation mode.
                 * Need to enqueue some Google Pay scripts to populate the billing form with details
                 * provided by Google Pay.
                 */
                if (is_checkout()) {
                    $button->enqueue();
                }
                if (has_block('woocommerce/checkout') || has_block('woocommerce/cart')) {
                    /**
                     * Should add this to the ButtonInterface.
                     *
                     * @psalm-suppress UndefinedInterfaceMethod
                     * @phpstan-ignore method.notFound
                     */
                    $button->enqueue_styles();
                }
            });
            // Enqueue backend scripts.
            add_action('admin_enqueue_scripts', static function () use ($c, $button) {
                if (!is_admin() || !$c->get('wcgateway.is-plugin-settings-page')) {
                    return;
                }
                /**
                 * Should add this to the ButtonInterface.
                 *
                 * @psalm-suppress UndefinedInterfaceMethod
                 * @phpstan-ignore method.notFound
                 */
                $button->enqueue_admin();
            });
            // Registers buttons on blocks pages.
            add_action('woocommerce_blocks_payment_method_type_registration', function (PaymentMethodRegistry $payment_method_registry) use ($c): void {
                $payment_method_registry->register($c->get('googlepay.blocks-payment-method'));
            });
            // Adds GooglePay component to the backend button preview settings.
            add_action('woocommerce_paypal_payments_admin_gateway_settings', function (array $settings): array {
                if (is_array($settings['components'])) {
                    $settings['components'][] = 'googlepay';
                }
                return $settings;
            });
            // Initialize AJAX endpoints.
            add_action('wc_ajax_' . UpdatePaymentDataEndpoint::ENDPOINT, static function () use ($c) {
                $endpoint = $c->get('googlepay.endpoint.update-payment-data');
                assert($endpoint instanceof UpdatePaymentDataEndpoint);
                $endpoint->handle_request();
            });
        }, 1);
        add_filter(
            'woocommerce_payment_gateways',
            /**
             * Param types removed to avoid third-party issues.
             *
             * @psalm-suppress MissingClosureParamType
             */
            static function ($methods) use ($c) {
                if (!is_array($methods)) {
                    return $methods;
                }
                $settings = $c->get('settings.settings-provider');
                assert($settings instanceof SettingsProvider);
                if (!$settings->googlepay_enabled()) {
                    return $methods;
                }
                $context = $c->get('button.helper.context');
                assert($context instanceof Context);
                $page_methods = $settings->button_styling($context->context())->methods;
                if (!in_array('ppcp-googlepay', $page_methods, \true)) {
                    return $methods;
                }
                $googlepay_gateway = $c->get('googlepay.wc-gateway');
                assert($googlepay_gateway instanceof WC_Payment_Gateway);
                $methods[] = $googlepay_gateway;
                return $methods;
            }
        );
        /**
         * Filters the available payment gateways to remove the Google Pay gateway
         * when the button is disabled for the current location (e.g., classic checkout) in the styling settings.
         * This is necessary because WooCommerce automatically includes the gateway when it is enabled,
         * even if the button is hidden via settings.
         */
        add_filter('woocommerce_available_payment_gateways', static function ($methods) use ($c) {
            if (!is_array($methods)) {
                return $methods;
            }
            $context = $c->get('button.helper.context');
            assert($context instanceof Context);
            $current_context = $context->context();
            if ($current_context !== 'checkout') {
                return $methods;
            }
            $settings = $c->get('settings.settings-provider');
            assert($settings instanceof SettingsProvider);
            $page_methods = $settings->button_styling($current_context)->methods;
            if (!in_array(\WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway::ID, $page_methods, \true)) {
                unset($methods[\WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway::ID]);
            }
            return $methods;
        });
        add_action('wp', static function () {
            $checkout_hook = (string) apply_filters('woocommerce_paypal_payments_checkout_button_renderer_hook', 'woocommerce_review_order_after_payment');
            add_action($checkout_hook, static function () {
                echo '<div id="ppc-button-' . esc_attr(\WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway::ID) . '"></div>';
            });
        });
        add_action('woocommerce_pay_order_after_submit', function () {
            echo '<div id="ppc-button-' . esc_attr(\WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway::ID) . '"></div>';
        });
        add_filter('woocommerce_paypal_payments_selected_button_locations', function (array $locations, string $setting_name): array {
            $gateway = WC()->payment_gateways()->payment_gateways()[\WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway::ID] ?? '';
            if ($gateway && $gateway->enabled === 'yes' && $setting_name === 'smart_button_locations') {
                $locations[] = 'checkout';
            }
            return $locations;
        }, 10, 2);
        add_filter('woocommerce_paypal_payments_rest_common_merchant_features', function (array $features) use ($c): array {
            $product_status = $c->get('googlepay.helpers.apm-product-status');
            assert($product_status instanceof GoogleProductStatus);
            $google_pay_enabled = $product_status->is_active();
            $features[FeaturesDefinition::FEATURE_GOOGLE_PAY] = array('enabled' => $google_pay_enabled);
            return $features;
        });
        add_filter('ppcp_create_order_request_body_data', static function (array $data, string $payment_method, array $request) use ($c): array {
            $funding_source = $request['funding_source'] ?? '';
            if ($payment_method !== \WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway::ID && $funding_source !== 'googlepay') {
                return $data;
            }
            $settings = $c->get('settings.settings-provider');
            assert($settings instanceof SettingsProvider);
            $experience_context_builder = $c->get('wcgateway.builder.experience-context');
            assert($experience_context_builder instanceof ExperienceContextBuilder);
            $payment_source_data = array('experience_context' => $experience_context_builder->with_endpoint_return_urls()->build()->to_array());
            $three_d_secure_contingency = $settings->three_d_secure_enum() ? apply_filters('woocommerce_paypal_payments_three_d_secure_contingency', $settings->three_d_secure_enum()) : '';
            if ($three_d_secure_contingency === 'SCA_ALWAYS' || $three_d_secure_contingency === 'SCA_WHEN_REQUIRED') {
                $payment_source_data['attributes'] = array('verification' => array('method' => $three_d_secure_contingency));
            }
            $data['payment_source'] = array('google_pay' => $payment_source_data);
            return $data;
        }, 10, 3);
        add_filter('woocommerce_paypal_payments_googlepay_button_styles', static function (LocationStylingDTO $styles): LocationStylingDTO {
            $styles->color = PropertiesDictionary::map_color($styles->color);
            $styles->label = PropertiesDictionary::map_type($styles->label);
            return $styles;
        }, 9999);
        add_filter('woocommerce_paypal_payments_googlepay_button_language', static function (string $language): string {
            return PropertiesDictionary::map_language($language);
        }, 9999);
        return \true;
    }
}
