<?php

namespace Soft_Tehnica\Freya_Sync_Service\Services;

use Soft_Tehnica\Freya_Sync_Service\Data\FSSResponse;
use Soft_Tehnica\Freya_Sync_Service\Data\PromoFee;
use Soft_Tehnica\Freya_Sync_Service\Data\Tax;
use Soft_Tehnica\Freya_Sync_Service\Data\UserAddress;
use Soft_Tehnica\Freya_Sync_Service\Data\UserAddressInputs;
use Soft_Tehnica\Freya_Sync_Service\Exceptions\SetAddressException;

class AddressService
{
    private static AddressService $instance;

    /**
     * @param array $data passed only if from multisite redirect
     * @return void
     * @throws SetAddressException
     */
    public function setLocationSettings(array $data): void
    {
        $pickup = isset($data['pickup']) && boolval($data['pickup']) === true;
        if ($pickup) {
            SessionService::get()->setIsPickup(true);
            SessionService::get()->setUserAddressInputs(null);
            SessionService::get()->setUserAddress(null);
            SessionService::get()->setAddress(null);
        } else {
            SessionService::get()->setIsPickup(false);
            if (!isset($data['geo'])) {
                throw new SetAddressException(
                    "Am primit date invalide de la API-ul Freya Sync",
                    500
                );
            }

            $address = new UserAddress(
                $data['geo']['id'],
                PluginSettings::get()->getCompanyUid(),
                $data['geo']['displayName'],
                $data['geo']['streetName'],
                $data['geo']['streetNumber'],
                $data['geo']['lat'],
                $data['geo']['lon'],
                $data['geo']['country'],
                $data['geo']['city'],
                $data['geo']['county'],
                $data['geo']['suburb'],
                $data['geo']['type']
            );
            SessionService::get()->setAddress($address);
            SessionService::get()->setUserAddress($address->displayName);

            $inputData = new UserAddressInputs(
                $data['geo']['streetNumber'],
                $data['blockNo'] ?? "",
                $data['entranceNo'] ?? "",
                $data['apartmentNo'] ?? "",
                $data['floor'] ?? ""
            );
            SessionService::get()->setUserAddressInputs($inputData);
        }
        $lat = $address->lat ?? '';
        $lon = $address->lon ?? '';
        $locationUid = $data['locationUid'] ?? PluginSettings::get()
            ->getDefaultLocationUid();

        $response = $this->fetchLocation(
            PluginSettings::get()->getCompanyUid(),
            $locationUid,
            $lat,
            $lon
        );

        if (!$response->status) {
            throw new SetAddressException(
                "Am întâmpinat o eroare la conectarea la API-ul Freya Sync",
                500
            );
        }
        if (isset($response->payload->taxes)) {
            $taxData = json_decode(
                json_encode($response->payload->taxes),
                true
            ) ?? [];
        } else {
            $taxData = null;
        }

        SessionService::get()->setLocationUid($locationUid);
        SessionService::get()->setLocationName($response->payload->name);
        $this->saveTaxes($taxData);

        $this->setCartLocationFromSession();

        // Force shipping recalculation
        WC()->session->set('previous_shipping_methods', null);
        WC()->session->set('chosen_shipping_methods', null);
        WC()->session->set('shipping_method_counts', null);
        WC()->session->set('shipping_for_package_0', null);
        WC()->session->save_data();
    }

    public function setCartLocationFromSession(): void
    {
        if (
            !wc()->cart ||
            PluginSettings::get()->isPolygonsDisabled()
        ) {
            return;
        }

        $pickup = SessionService::get()->isPickup();
        if ($pickup) {
            wc()->cart->get_customer()->set_billing_address_to_base();
            wc()->cart->get_customer()->set_shipping_address_to_base();
            return;
        }

        $address = SessionService::get()->getAddress();
        if (!$address) {
            return;
        }

        wc()->cart->get_customer()->set_billing_address($address->displayName);
        wc()->cart->get_customer()->set_billing_city($address->city);
        wc()->cart->get_customer()->set_shipping_address($address->displayName);
        wc()->cart->get_customer()->set_shipping_city($address->city);
    }

    /**
     * @ajax fss_set_location_settings_multisite
     *
     * @param string $b64
     * @return void
     * @throws SetAddressException
     */
    public function setLocationSettingsMultisite(string $b64): void
    {
        $data = json_decode(base64_decode($b64), true);
        $this->setLocationSettings($data);
    }

    public function saveTaxes(?array $data): ?Tax
    {
        if (!isset($data) || count($data) === 0) {
            SessionService::get()->setTax(null);
            return null;
        }
        $promotions = [];
        if (isset($data['promoFees'])) {
            foreach ($data['promoFees'] as $promotion) {
                if (!isset($promotion['promotionThreshold']) || !isset($promotion['promotionFee'])) {
                    continue;
                }
                try {
                    $promotions[] = new PromoFee(
                        $promotion['promotionFee'],
                        $promotion['promotionThreshold'],
                        $promotion['message']
                    );
                } catch (\Throwable $e) {
                    continue;
                }
            }
        }

        $tax = new Tax(
            $data['tax'],
            $data['cost'],
            $promotions,
            $data['minimumFee']
        );
        SessionService::get()->setTax($tax);
        return $tax;
    }

    private function fetchLocation(
        string $companyUid,
        string $locationUid,
        string $latitude = '',
        string $longitude = ''
    ): FSSResponse {
        return makeHttpPost(
            'api/wp/getLocationSettings',
            [
                'locationUid' => $locationUid,
                'companyUid' => $companyUid,
                'lat' => $latitude,
                'lon' => $longitude
            ]
        );
    }

    /**
     * @ajax fss_set_location_settings
     *
     * @return void
     */
    public function setLocationSettingsAjax(): void
    {
        if (!defined("DOING_AJAX")) {
            return;
        }
        check_ajax_referer('wp_rest', 'nonce');
        try {
            $this->setLocationSettings($_POST);
            wp_send_json_success();
        } catch (SetAddressException $e) {
            if (defined('FSS_DOCKER')) {
                $message = [
                    'message' => $e->getMessage(),
                    'trace' => $e->getTrace(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine()
                ];
            } else {
                $message = [
                    'message' => $e->getMessage()
                ];
            }
            wp_send_json_error($message, $e->getCode());
        } catch (\Throwable $e) {
            if (defined('FSS_DOCKER')) {
                $message = [
                    'message' => $e->getMessage(),
                    'trace' => $e->getTrace(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine()
                ];
            } else {
                $message = [
                    'message' => 'Am întâmpinat o eroare necunoscută'
                ];
            }
            wp_send_json_error($message, 500);
        }
    }


    protected function __construct()
    {
        if (!PluginSettings::get()->isPolygonsDisabled()) {
            add_action(
                'wp_ajax_nopriv_fss_set_location_settings',
                [$this, 'setLocationSettingsAjax'],
                1
            );
            add_action(
                'wp_ajax_fss_set_location_settings',
                [$this, 'setLocationSettingsAjax'],
                1
            );
        }

        if (isset($_GET['redirect-payload']) && PluginSettings::get(
            )->isEnableMultiSubdomain()) {
            $payload = json_decode(
                base64_decode($_GET['redirect-payload']),
                true
            );
            try {
                $this->setLocationSettings($payload);
            } catch (\Throwable $e) {
            }
        }
    }

    protected function __clone()
    {
    }

    public static function get(): AddressService
    {
        if (!isset(static::$instance)) {
            static::$instance = new AddressService();
        }

        return static::$instance;
    }
}