<?php

namespace Soft_Tehnica\Freya_Sync_Service\Services;

use WC_Order;
use WP_Error;
use WP_Query;
use Exception;
use WP_REST_Request;
use WP_REST_Response;
use WC_Shipping_Zones;
use WC_Shipping_Method;
use Soft_Tehnica\Freya_Sync_Service\STUtils\STView;
use Soft_Tehnica\Freya_Sync_Service\Data\FsPickupMethod;
use Soft_Tehnica\Freya_Sync_Service\Data\FsShippingMethod;
use Soft_Tehnica\Freya_Sync_Service\Services\AddressService;
use Soft_Tehnica\Freya_Sync_Service\Services\PluginSettings;
use Soft_Tehnica\Freya_Sync_Service\Services\SessionService;
use Soft_Tehnica\Freya_Sync_Service\Services\LocationService;
use WC_Product;

class CartService
{
    public string $modalAddressContent = "";
    public string $needAddressAlert = "";
    public string $needAddressMinimalAlert = "";
    public string $needAddressInfo = "";
    public string $needAddressLink = "";
    public string $noAddressContent = "";
    public ?string $countyRestriction;
    public ?string $companyUid;
    public ?string $defaultLocationUid;
    public array $addressOnPages = [];
    public $addressRequestOnPages;
    public $enableMultiSubdomain;
    public $isRunningOnLandingPageInstance;
    public bool $isRestApi = false;
    public ?string $noAddressFoundMessage;
    public bool $noPolygons;
    public bool $showAllProductsOnNoLocation = false;
    public bool $needToAskAddressOnLoad = true;
    public bool $triggerModalAddressAuto = true;

    private bool $fsShippingEnabled = false;
    private bool $fsPickupEnabled = false;

    public function __construct()
    {
        $this->setLocalData();
        $this->init();
        $zones = WC_Shipping_Zones::get_zones();
        foreach ($zones as $zone) {
            /** @var WC_Shipping_Method $method */
            foreach ($zone["shipping_methods"] as $method) {
                if ($method->id === "fs_pickup_method" && $method->enabled === "yes") {
                    $this->fsPickupEnabled = true;
                }
                if ($method->id === "fs_shipping_method" && $method->enabled === "yes") {
                    $this->fsShippingEnabled = true;
                }
            }
        }

        SessionService::get()->updateSessionWithActiveShipping(
            $this->fsShippingEnabled,
            $this->fsPickupEnabled
        );
        $availableLocations = LocationService::get()->getAvaliableLocations();
        SessionService::get()->setFetchedLocations($availableLocations);

        AddressService::get()->setCartLocationFromSession();

        $this->modalAddressContent = $this->renderModal();
        $this->needAddressAlert = $this->renderNeedAddressContent();
        $this->needAddressMinimalAlert = $this->renderNeedAddressMinimalContent();
        $this->noAddressContent = $this->renderNoAddress();

        $this->needAddressInfo = STView::render('need-address-info', [
            'address' => SessionService::get()->getUserAddress(),
            'pickup' => SessionService::get()->isPickup(),
            'locationName' => SessionService::get()->getLocationName(),
        ]);
        $this->needAddressLink = STView::render('need-address-link');

        add_shortcode("fss_need_address", [$this, "need_address_shortcode"]);
        add_shortcode("fss_need_address_minimal", [$this, "need_address_minimal_shortcode"]);
        add_shortcode("fss_need_address_info", [$this, "need_address_info_shortcode"]);
        add_shortcode("fss_need_address_link", [$this, "need_address_link_shortcode"]);
    }

    public function need_address_shortcode(): string
    {
        return $this->needAddressAlert;
    }

    public function need_address_minimal_shortcode(): string
    {
        return $this->needAddressMinimalAlert;
    }

    public function need_address_info_shortcode(): string
    {
        return $this->needAddressInfo;
    }

    public function need_address_link_shortcode(): string
    {
        return $this->needAddressLink;
    }

    public function setLocalData(): void
    {
        $options = get_option('fs_option_settings', array());

        $this->companyUid = (isset($options['fsCompanyUid'])) ? $options['fsCompanyUid'] : null;
        $this->defaultLocationUid = (isset($options['fsDefaultLocationUid'])) ? $options['fsDefaultLocationUid'] : null;
        $this->addressOnPages = (isset($options['fsAddressRequestOnPages'])) ? $options['fsAddressRequestOnPages'] : [];
        $this->enableMultiSubdomain = (isset($options['fsEnableMultiSubdomain'])) ? $options['fsEnableMultiSubdomain'] : null;
        $this->isRunningOnLandingPageInstance = (isset($options['fsIsRunningOnLandingPageInstance'])) ? $options['fsIsRunningOnLandingPageInstance'] : null;
        $this->countyRestriction = (isset($options['fsCountyRestriction'])) ? $options['fsCountyRestriction'] : null;
        $this->noAddressFoundMessage = (isset($options['fsNoAddressFoundMessage'])) ? $options['fsNoAddressFoundMessage'] : null;
        $this->noPolygons = isset($options['fsNoPolygons']) && $options['fsNoPolygons'] === 1;
        $this->showAllProductsOnNoLocation = PluginSettings::get()->getShowAllProductsOnNoLocation();
    }

    public function renderNeedAddressContent(): string
    {
        return STView::render('need-address', [
            'address' => SessionService::get()->getUserAddress(),
            'pickup' => SessionService::get()->isPickup(),
            'hasDelivery' => $this->fsShippingEnabled,
            'hasPickup' => $this->fsPickupEnabled,
            'locationName' => SessionService::get()->getLocationName(),
            'minimal' => false
        ]);
    }

    public function renderNeedAddressMinimalContent(): string
    {
        return STView::render('need-address', [
            'address' => SessionService::get()->getUserAddress(),
            'pickup' => SessionService::get()->isPickup(),
            'hasDelivery' => $this->fsShippingEnabled,
            'hasPickup' => $this->fsPickupEnabled,
            'locationName' => SessionService::get()->getLocationName(),
            'minimal' => true
        ]);
    }

    public function renderModal(): string
    {
        return STView::render('modal-address', [
            'noAddressMessage' => $this->noAddressFoundMessage,
            'pickup' => SessionService::get()->isPickup(),
            'userAddress' => SessionService::get()->getUserAddress(),
            'hasPickup' => $this->fsPickupEnabled,
            'hasDelivery' => $this->fsShippingEnabled,
            'activeLocationUid' => SessionService::get()->getLocationUid(),
            'locations' => SessionService::get()->getFetchedLocations(),
            'hasFA' => is_plugin_active('font-awesome/index.php'),
            'hideDismiss' => PluginSettings::get()->hideModalDismiss()
        ]);
    }

    public function renderNoAddress(): string
    {
        return STView::render('no-address');
    }

    public function check_cart_item_locations(): void {
        if (!wc()->cart) {
            error_log("FSS - Failed to check cart for invalid items. Cart is null.");
            return;
        }

        $locationUid = SessionService::get()->getLocationUid()
            ?? PluginSettings::get()->getDefaultLocationUid();

        $locationName = SessionService::get()->getLocationName() ?? ' - ';

        if (!isset($locationUid)) {
            return;
        }

        foreach (wc()->cart->get_cart() as $k => $item) {
            /** @var \WC_Product|null $product */
            $product = $item['data'];

            if (!$product) {
                error_log("FSS - Product has null data.");
                continue;
            }

            /** @var array<string, array{name: string, price: float}>|null $ext */
            $ext = $product->get_meta('location_ext');
            /** @var string|null $locationUid */
            $productLocationUid = $product->get_meta('location_uid');

            $found = false;

            if (is_string($productLocationUid) && $locationUid === $productLocationUid) {
                $found = true;
            }

            if (is_array($ext)) {
                foreach ($ext as $uid => $data) {
                    if ($uid === $locationUid) {
                        $found = true;
                        break;
                    }
                }
            }

            if (!$found) {
                wc()->cart->remove_cart_item($k);
                wc_add_notice(
                    "Produsul {$product->get_name()} nu este disponibil în locația $locationName. Acesta a fost eliminat din coșul dumneavoastră.",
                    "error"
                );
            }
        }
    }

    public function isAddressSet(): bool
    {
        if (SessionService::get()->isPickup()) {
            return true;
        }
        $userAddress = SessionService::get()->getUserAddress();
        return isset($userAddress) && strlen($userAddress) > 0;
    }

    public function isProductInActiveLocation(WC_Product $product): bool
    {
        $locationUid = SessionService::get()->getLocationUid()
            ?? PluginSettings::get()->getDefaultLocationUid();

        if (!isset($locationUid)) {
            return false;
        }

        $meta = $product->get_meta('location_uid');

        /** @var array<string, array{name: string, price: float}>|false $ext */
        $ext = $product->get_meta('location_ext');

        if ($ext) {
            foreach ($ext as $uid => $value) {
                if ($uid === $locationUid) {
                    return true;
                }
            }
        }

        if ($meta && $meta === $locationUid) {
            return true;
        }

        return false;
    }

    /**
     * @hook woocommerce_add_to_cart_validation
     * 
     * Folosit pentru pagina de produs și versiuni mai vechi de woocommerce (fără ajax)
     * 
     * @param bool $passed
     * @param int $product_id
     * 
     * @return boolean
     */
    public function validate_cart_item_old(bool $passed, int $product_id): bool {
        // Dacă suntem în store API, lăsăm celălalt hook să-și facă treaba
        if (fss_is_wc_store_api()) {
            return $passed;
        }

        if (!$this->isAddressSet()) {
            SessionService::get()->setFlashNeedLocation(true);
            return false;
        }

        $product = wc_get_product($product_id);

        if (!$product) {
            return $passed;
        }

        if (!$this->isProductInActiveLocation($product)) {
            wc_add_notice('Acest produs nu este servit de locația selectată', 'error');

            return false;
        }
        return $passed;
    }

    /**
     * @hook woocommerce_store_api_validate_add_to_cart
     * 
     * woocommerce >= 7.2
     * 
     * Pentru adăugarea în coș prin ajax (store api)
     * 
     * @param WC_Product $product
     * @return void
     */
    public function validate_cart_item_new(WC_Product $product): void
    {
        if (!$this->isAddressSet()) {
            throw new Exception("Nu s-a putut adăuga produsul în coș deoarece nu ați ales locația de servire.", 400);
        }

        if (!$this->isProductInActiveLocation($product)) {
            throw new Exception("Acest produs nu este servit de locația de servire activă", 400);
        }
    }

    public function finalHtmlResponse($wpPageContent): string
    {
        $content = $wpPageContent . $this->modalAddressContent;
        $pageId = get_queried_object_id();

        $modalDismissed = SessionService::get()->isAddressModalDismissed();

        $userAddressDetails = SessionService::get()->getUserAddressInputs();

        $PAGE_SHOULD_SHOW_MODAL = in_array(
            $pageId,
            PluginSettings::get()->getPagesThatRequestAddress()
        );
        $COMPANY_HAS_POLYGONS = PluginSettings::get()->isPolygonsDisabled();
        $USER_ADDRESS_SET = isset($userAddressDetails);

        if (
            $PAGE_SHOULD_SHOW_MODAL &&
            $this->triggerModalAddressAuto &&
            !$modalDismissed &&
            $COMPANY_HAS_POLYGONS &&
            !$USER_ADDRESS_SET
        ) {
            $content .= "<script> const j = jQuery.noConflict(); j.('#fss-modal').addClass('modal-visible') </script>";
        }

        return $content;
    }

    public function setMinimOrderValue(): void
    {
        if (is_admin() && !defined('DOING_AJAX')) {
            return;
        }

        $taxData = SessionService::get()->getTax();

        if (is_null($taxData) || $taxData->minimumFee === 0.) {
            return;
        }

        if (floatval(WC()->cart->get_displayed_subtotal()) < $taxData->minimumFee) {
            $value = number_format($taxData->minimumFee, 2);
            $diffValue = number_format(
                abs(floatval(WC()->cart->get_displayed_subtotal()) - $taxData->minimumFee),
                2
            );

            $message = sprintf(
                "Comanda minimă pentru adresa dumnavoastră este în valoare de %f RON.\nMai trebuie să adăugați produse în valoare de %f RON pentru a finaliza comanda.",
                $value,
                $diffValue
            );

            wc_clear_notices();
            wc_add_notice($message, 'error');
        }
    }

    public function destroySession(): void
    {
        SessionService::get()->clearSession();
    }

    public function initRestApi($args): void
    {
        if ($args) {
            $this->isRestApi = true;
        }
    }

    public function filterProductsByLocation(\WP_Query $query): void
    {
        if (!$query->is_main_query()) {
            return;
        }

        $locationUid = SessionService::get()->getLocationUid();

        if (is_null($locationUid) && $this->showAllProductsOnNoLocation) {
            return;
        } else if (is_null($locationUid)) {
            $locationUid = PluginSettings::get()->getDefaultLocationUid();
        }

        if (is_null($locationUid)) {
            return;
        }

        $query->set('meta_query', [
            'relation' => 'OR',
            [
                'key' => 'location_uid',
                'compare' => '=',
                'value' => "$locationUid"
            ],
            [
                'key' => 'location_ext',
                'compare' => 'LIKE',
                'value' => "$locationUid"
            ]
        ]);
    }

    /**
     * @ajax cart_service_service_modal_dismissed
     *
     * @return void
     */
    public function setModalDismissed(): void
    {
        SessionService::get()->setAddressModalDismissed(true);
    }

    public function onOrderPlaced($id): void
    {
        SessionService::get()->clearSession();
    }

    public function onWoocommerceBillingFields(array $fields): array
    {
        $fields["billing"]["billing_email"]["required"] = false;

        return $fields;
    }

    public function customizeCheckoutAddressFields(array $fields): array
    {
        if (SessionService::get()->isPickup()) {
            $fields["address_1"]["required"] = false;
            $fields["country"]["required"] = false;
            $fields["city"]["required"] = false;
            $fields["state"]["required"] = false;
            $fields["postcode"]["required"] = false;
            return $fields;
        }
        $city = null;
        $address = SessionService::get()->getAddress();
        $userInputs = SessionService::get()->getUserAddressInputs();
        if ($address) {
            if ($address->suburb !== '') {
                $city = $address->suburb;
            }
            if ($address->county !== "") {
                $city = $address->county;
            }
            if ($address->city !== "") {
                $city = $address->city;
            }
        }
        if (!$city) {
            $city = 'Neidentificat';
        }

        $fields["street_number"] = [
            "type" => "text",
            "label" => "Număr stradă",
            "priority" => 61,
            "default" => $address->streetNumber ?? "",
            "value" => $address->streetNumber ?? "",
        ];
        if ($address) {
            $fields["city"]["custom_attributes"] = [
                "readonly" => "readonly"
            ];
            $fields["city"]["default"] = $city;
            $fields["city"]["value"] = $city;
            unset($fields["city"]["autocomplete"]);

            $fields["address_1"]["custom_attributes"] = [
                "readonly" => "readonly"
            ];
            $fields["address_1"]["default"] = $address->displayName;
            $fields["address_1"]["value"] = $address->displayName;
            unset($fields["address_1"]["autocomplete"]);
            unset($fields["address_2"]);
        }
        $fields["unit"] = [
            "type" => "text",
            "label" => "Bloc",
            "priority" => 62,
            "default" => $userInputs->block ?? "",
            "value" => $userInputs->block ?? ""
        ];
        $fields["staircase"] = [
            "type" => "text",
            "label" => "Scară",
            "priority" => 63,
            "default" => $userInputs->entrance ?? "",
            "value" => $userInputs->entrance ?? "",
        ];
        $fields["floor"] = [
            "type" => "text",
            "label" => "Etaj",
            "priority" => 64,
            "default" => $userInputs->floor ?? "",
            "value" => $userInputs->floor ?? "",
        ];
        $fields["apartment"] = [
            "type" => "text",
            "label" => "Apartament",
            "priority" => 65,
            "default" => $userInputs->apartment ?? "",
            "value" => $userInputs->apartment ?? "",
        ];

        return $fields;
    }

    public function processPaymentGateways($pMethods)
    {
        return $pMethods;
    }

    private function getLocationNameFromAPI(): ?string
    {
        $res = makeHttpGet(
            "api/wp/getLocation/?uid={$this->defaultLocationUid}"
        );
        if (isset($res->payload->name)) {
            return $res->payload->name;
        }
        return null;
    }

    public function displayFieldsOnProductPage(): void
    {
        $this->displayProductCommentary();
    }

    private function displayProductCommentary(): void
    {
        woocommerce_form_field(
            'freya_sync_commentary',
            [
                'type' => 'textarea',
                'class' => ['freya_sync_commentary', 'form-row-wide'],
                'label' => __('Comentariu', 'woocommerce'),
                'id' => 'freya_sync_commentary',
            ]
        );
    }

    public function prepare_notices(): void
    {
        if (strlen($this->needAddressAlert) === 0) {
            ?>
            <div>Am întâmpinat o eroare cu crearea widget-ului Freya Sync.</div>
            <?php
        } else {
            echo $this->needAddressAlert;
        }
    }

    public function before_add_to_cart_form(): void
    {
        $product = wc_get_product();

        if (!$product) {
            return;
        }

        $this->add_location_notice($product);
        $this->add_returo_notice($product);
    }

    private function add_location_notice(\WC_Product $product): void
    {
        if (!$product->meta_exists('location_ext')) {
            return;
        }

        /** @var array<string, array{name: string, price: float}|false $ext */
        $ext = $product->get_meta('location_ext');

        if (!$ext) {
            return;
        }

        $names = array_map(function ($item) {
            return $item['name'];
        }, $ext);

        ?>
        <div class="fss-product-availability">
            Disponibil în locațiile: <strong><?php echo implode(', ', $names) ?></strong>
        </div>
        <?php
    }

    private function add_returo_notice(\WC_Product $product): void
    {
        if (!$product->meta_exists('returo_units')) {
            return;
        }

        /** @var int $hasReturo */
        $hasReturo = intval($product->get_meta('returo_units'));

        if ($hasReturo === 0) {
            return;
        }

        $returoPrice = $hasReturo * 0.5;

        ?>
        <div class="fss-returo-notice">
            Prețul <strong>nu</strong> include garanția SGR (<?php echo sprintf("%.2f lei", $returoPrice) ?>)
        </div>
        <?php
    }

    public function addProductFieldsToCartItem(
        $cart_item_data,
        $product_id
    ): array {
        if (isset($_POST['freya_sync_commentary'])) {
            $cart_item_data['freya_sync_commentary'] = sanitize_text_field(
                $_POST['freya_sync_commentary']
            );
        }

        return $cart_item_data;
    }

    public function addProductFieldsToOrderItem(
        $item,
        $cart_item_key,
        $values,
        $order
    ) {
        if (isset($values['freya_sync_commentary'])) {
            $item->add_meta_data(
                'freya_sync_commentary',
                $values['freya_sync_commentary'],
                true
            );
        }

        return $item;
    }

    public function validateCartOnSubmit($fields, $errors): void
    {
        if ($this->noPolygons || SessionService::get()->isPickup()) {
            return;
        }

        $userAddress = SessionService::get()->getUserAddress();
        if (!$userAddress || strlen($userAddress) === 0) {
            $errors->add(
                'validation',
                'Adresa de livrare nu este setată! <b style="cursor: pointer" class="address-modal-open">Te rugăm să selectezi o adresă de livrare</b>.'
            );
        }
    }

    /**
     * @hook woocommerce_checkout_create_order
     * 
     * Rulează **la checkout**
     * 
     * Din ceva motiv, save_meta_data() nu aplică datele extra, deci nu apelăm aici
     *
     * @param WC_Order $order
     * @return void
     */
    public function order_created_old(WC_Order $order): void
    {
        $this->add_meta_to_order($order);
    }

    /**
     * @hook woocommerce_store_api_checkout_update_order_meta
     * 
     * Pentru interfața nouă cu blocks, rulează **când se intră pe pagina de checkout și după checkout**
     *
     * @param WC_Order $order
     * @return void
     */
    public function order_created_new(WC_Order $order): void
    {
        $this->add_meta_to_order($order);
        $order->save_meta_data();
    }

    private function add_meta_to_order(WC_Order $order): void
    {
        $locationName = SessionService::get()->getLocationName();
        $locationUid = SessionService::get()->getLocationUid() ?? PluginSettings::get()->getDefaultLocationUid();
        if (is_null($locationName) && $this->noPolygons) {
            $locationName = $this->getLocationNameFromAPI();
            SessionService::get()->setLocationName($locationName);
        }

        $items = $order->get_items();

        foreach ($items as $item) {
            $data = $item->get_data();
            if (isset($data['freya_sync_toppings'])) {
                $item->update_meta_data(
                    'freya_sync_toppings',
                    $data['freya_sync_toppings']
                );
                $item->save();
                $item->save_meta_data();
            }
        }

        $address = SessionService::get()->getAddress() ?? null;
        if (isset($address)) {
            $order->update_meta_data('freya-sync-address-id', $address->id);
            $order->update_meta_data('freya-sync-address-type', $address->type);
        }

        if (!isset($locationName) || !isset($locationUid)) {
            $order->update_meta_data(
                'freya-sync-error',
                'Nu am putut asocia aceasta comandă unei locații'
            );
            $order->update_meta_data('freya-sync-processed', 'false');
            return;
        }

        $order->update_meta_data('location_uid', $locationUid);
        $order->update_meta_data('location_name', $locationName);
        $order->update_meta_data('freya-sync-uid', '');
        $order->update_meta_data('freya-order-id', '');
        $order->update_meta_data('freya-sync-error', '');
        $order->update_meta_data('freya-sync-processed', '');
    }

    public function getOrdersApiRoute(WP_REST_Request $request)
    {
        if (is_user_logged_in()) {
            return new WP_REST_Response('ok', 200);
        }

        return new WP_Error(
            'unauthorized',
            __('You shall not pass'),
            ['status' => 401]
        ); //can also use WP_REST_Response
    }

    public function ajaxClearSession(): void
    {
        $this->destroySession();
        wp_send_json_success();
    }

    public function registerShippingMethod($methods): array
    {
        $methods['fs_shipping_method'] = new FsShippingMethod();
        $methods['fs_pickup_method'] = new FsPickupMethod();

        return $methods;
    }

    /**
     * @param string $price
     * @param \WC_Product $product
     * @return string
     */
    public function modify_product_price(string $price, \WC_Product $product): string
    {
        if (is_admin()) {
            return $price;
        }

        $locationUid = SessionService::get()->getLocationUid()
            ?? PluginSettings::get()->getDefaultLocationUid();

        if (is_null($locationUid)) {
            return $price;
        }

        // Call in edit context to not recurse with hooks
        if ($product->get_regular_price('edit') === $product->get_price('edit')) {
            return $this->modify_product_regular_price($price, $product);
        }

        return $price;
    }

    /**
     * @param string $price
     * @param \WC_Product $product
     * @return string
     */
    public function modify_product_regular_price(string $price, \WC_Product $product): string
    {
        if (is_admin()) {
            return $price;
        }

        $locationUid = SessionService::get()->getLocationUid()
            ?? PluginSettings::get()->getDefaultLocationUid();

        if (is_null($locationUid)) {
            return $price;
        }

        /** @var array<string, array{name: string, price: float}>|false $ext */
        $ext = $product->get_meta('location_ext');

        if (!$ext) {
            return $price;
        }

        foreach ($ext as $uid => $value) {
            if ($uid !== $locationUid) {
                continue;
            }

            return wc_float_to_string((float)$value['price']);
        }

        return $price;
    }

    public function breadcrumb(): void
    {
        if (!SessionService::get()->flashNeedLocation()) {
            return;
        }

        echo $this->noAddressContent;
        SessionService::get()->setFlashNeedLocation(false);
    }

    public function init(): void
    {
        if (isset($_GET['redirect-payload'])) {
            AddressService::get()->setLocationSettingsMultisite(
                $_GET['redirect-payload']
            );
        }
        if (!$this->noPolygons) {
            add_action(
                'wp_ajax_nopriv_cart_clear_session',
                [$this, 'ajaxClearSession'],
                1
            );
            add_action(
                'wp_ajax_cart_clear_session',
                [$this, 'ajaxClearSession'],
                1
            );

            // Create public route for address modal dismissed
            add_action(
                'wp_ajax_nopriv_cart_service_service_modal_dismissed',
                [$this, 'setModalDismissed'],
                1
            );
            add_action(
                'wp_ajax_cart_service_service_modal_dismissed',
                [$this, 'setModalDismissed'],
                1
            );

            // Validare coș (fără ajax)
            add_filter('woocommerce_add_to_cart_validation', [$this, 'validate_cart_item_old'], 10, 2);
            // Validare coș (cu ajax) - woocommerce >= 7.1
            add_filter('woocommerce_store_api_validate_add_to_cart', [$this, 'validate_cart_item_new']);

            // Add extra taxes to cart
            add_action(
                'woocommerce_cart_calculate_fees',
                [$this, 'setMinimOrderValue'],
                1
            );

            // Register shipping method
            add_filter(
                'woocommerce_shipping_methods',
                [$this, 'registerShippingMethod'],
                1,
                1
            );

            // Hook on edit billing address
            add_filter(
                'woocommerce_checkout_fields',
                [$this, 'onWoocommerceBillingFields'],
                10,
                2
            );
            add_filter(
                "woocommerce_default_address_fields",
                [$this, "customizeCheckoutAddressFields"]
            );

            add_filter(
                'woocommerce_after_checkout_validation',
                [$this, 'validateCartOnSubmit'],
                10,
                2
            );

            add_action(
                'woocommerce_before_shop_loop',
                [$this, 'prepare_notices'],
                10
            );
            add_action(
                'woocommerce_before_single_product',
                [$this, 'prepare_notices'],
                99
            );
            add_action(
                'woocommerce_before_add_to_cart_form',
                [$this, 'before_add_to_cart_form'],
                10
            );

            add_filter('pre_get_posts', function (WP_Query $query) {
                if (!is_admin() && (is_shop() || is_search() || is_product_category())) {
                    $this->filterProductsByLocation($query);
                }
            });

            add_action('template_redirect', function () {
                if ($this->needToAskAddressOnLoad && $this->isRestApi === false) {
                    ob_start([$this, 'finalHtmlResponse']);
                }
            });
        }

        // Add extra fields on product page
        add_action(
            'woocommerce_before_add_to_cart_button',
            array($this, 'displayFieldsOnProductPage')
        );
        add_filter(
            'woocommerce_add_cart_item_data',
            array($this, 'addProductFieldsToCartItem'),
            11,
            2
        );
        add_filter(
            'woocommerce_checkout_create_order_line_item',
            array($this, 'addProductFieldsToOrderItem'),
            11,
            4
        );

        add_action('woocommerce_cart_loaded_from_session', [$this, 'check_cart_item_locations'], 10);
        add_action(
            'woocommerce_available_payment_gateways',
            [$this, 'processPaymentGateways'],
            10,
            1
        );

        // Detect if is a rest call api
        add_action('rest_api_init', [$this, 'initRestApi']);

        // Creare comandă - interfață veche și cea nouă bazată pe blocks
        add_filter('woocommerce_checkout_create_order', [$this, 'order_created_old']);
        add_filter('woocommerce_store_api_checkout_update_order_meta', [$this, 'order_created_new']);

        // Action on order is placed - unset session
        add_action('woocommerce_thankyou', [$this, 'onOrderPlaced'], 10, 1);

        add_action('woocommerce_breadcrumb', [$this, 'breadcrumb']);

        add_action('woocommerce_product_get_price', [$this, 'modify_product_price'], 10, 2);
        add_action('woocommerce_product_get_regular_price', [$this, 'modify_product_regular_price'], 10, 2);
    }
}
