<?php

namespace KupShop\ComponentsBundle\GTM\Events;

use KupShop\CatalogBundle\Util\ActiveCategory;
use KupShop\GTMBundle\ServerSideGTMEvent\FetchUsersStatsOrderData;
use KupShop\GTMBundle\Utils\DataLoaders\PurchaseState;
use KupShop\GTMBundle\Utils\PriceComputer;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\OrderingBundle\Cart;
use KupShop\OrderingBundle\Util\Order\DeliveryInfo;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use KupShop\PricelistBundle\Context\PricelistContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

class Purchase
{
    use FetchUsersStatsOrderData;

    public function __construct(
        protected Cart $cart,
        protected PriceComputer $priceComputer,
        protected RequestStack $requestStack,
        protected ActiveCategory $activeCategory,
        protected ?LanguageContext $languageContext,
        protected ?CurrencyContext $currencyContext,
        protected ?PricelistContext $pricelistContext,
        protected OrderInfo $orderInfo,
        protected PurchaseState $purchaseStateLoader,
        protected DeliveryInfo $deliveryInfo,
        protected \KupShop\ComponentsBundle\GTM\Utils\DataLoaders\Products $productLoader,
    ) {
    }

    protected $pageData;

    /**
     * Specific PageData.
     *
     * @throws \Exception
     */
    public function getData(&$dataContainer)
    {
        $dbcfg = \Settings::getDefault();

        $order = $this->pageData['body']['order'];

        if (!empty($order) && $order instanceof \Order && !$order->getData('conversion_sent')) {
            $orderVAT = $this->priceComputer->getPrice($order->total_price_array['value_vat']);

            $discounts = $this->purchaseStateLoader->getDiscountsForFE($order->getPurchaseState(true));

            $dataContainer->event = 'purchase';

            if (!empty($order->invoice_name)) {
                $dataContainer->user = $dataContainer->user ?? new \stdClass();
                $dataContainer->user->name = $order->invoice_name;
                $dataContainer->user->surname = $order->invoice_surname;
                $dataContainer->user->email = $order->invoice_email;
                $dataContainer->user->phone = $order->invoice_phone;
                $dataContainer->user->address = [
                    'street' => $order->invoice_street,
                    'city' => $order->invoice_city,
                    'region' => $order->invoice_state,
                    'postal_code' => $order->invoice_zip,
                    'country' => $order->invoice_country,
                ];
            }

            $purchase = new \stdClass();
            $purchase->transaction_id = $order->order_no;

            $deliveryType = $order->getDeliveryType();
            $delivery = $deliveryType->getDelivery();
            $payment = $deliveryType->getPayment();

            $purchase->payment = [
                'type' => $payment?->getClassName() ?? '',
                'method' => [
                    'id' => $payment?->method ?? null,
                ],
            ];
            $purchase->shipping_tier = [
                'type' => $delivery?->getClassName() ?? '',
            ];

            $currency = $this->priceComputer->getOutputCurrency();
            $purchase->currency = $currency->getId();

            $shippingPrice = $this->getDeliveryPrice($order);
            $shippWithVat = $shippingPrice['value_with_vat'] ?? \DecimalConstants::zero();
            $shippWithoutVat = $shippingPrice['value_without_vat'] ?? \DecimalConstants::zero();
            $purchase->shipping = $this->priceComputer->getPrice($shippingPrice ?? toDecimal(0));
            $purchase->shipping_with_tax = $this->priceComputer->getPrice($shippWithVat);
            $purchase->shipping_without_tax = $this->priceComputer->getPrice($shippWithoutVat);

            if (($dbcfg->analytics['google_tag_manager']['withoutDelivery'] ?? 'N') == 'Y') {
                $tp = toDecimal($this->priceComputer->getPrice($order->getTotalPrice()));
                $shipp = toDecimal($purchase->shipping);
                $purchase->value = $tp->sub($shipp);
                $purchase->value_with_tax = $this->priceComputer->getPrice($order->getTotalPrice()->getPriceWithVat()->sub($shippWithVat), round: false);
                $purchase->value_without_tax = $this->priceComputer->getPrice($order->getTotalPrice()->getPriceWithoutVat()->sub($shippWithoutVat), round: false);
            } else {
                $purchase->value = $this->priceComputer->getPrice($order->getTotalPrice(), round: false);
                $purchase->value_with_tax = $this->priceComputer->getPrice($order->getTotalPrice()->getPriceWithVat(), round: false);
                $purchase->value_without_tax = $this->priceComputer->getPrice($order->getTotalPrice()->getPriceWithoutVat(), round: false);
            }

            $purchase->value_without_tax_and_shipping = $this->priceComputer->getPrice($order->getTotalPrice()->getPriceWithoutVat()->sub(toDecimal($shippingPrice['value_without_vat'] ?? 0)), round: false);

            $purchase->tax = $orderVAT;
            $purchase->flags = array_filter(array_keys($order->getFlags()));

            if ($coupons = OrderInfo::getUsedCoupons($order)) {
                $coupons = join(',', $coupons);
            }
            $purchase->coupons = $coupons ?: '';

            $purchase->heureka_disagree = $order->getData('heurekaDisagree');

            $purchase->discounts = $discounts;

            $purchase->items = [];

            $order->productList->fetchVariations(true);
            $order->productList->fetchSections();
            $order->productList->fetchProducers();
            $order->productList->fetchMainImages(1);
            foreach ($order->fetchItems() as $item) {
                if ($item['id_product']) {
                    $p = $this->productLoader->getProductObject($item['product']);

                    $p->quantity = $item['pieces'];
                    if ($p->category_current == '@breadcrumbs') {
                        $p->category_current = [];
                    }

                    $prices = $this->purchaseStateLoader->getPrices($item);
                    $p->price = $prices['price'];
                    $p->price_with_tax = $prices['priceWithVat'];
                    $p->price_without_tax = $prices['priceWithoutVat'];
                    $p->price_tax = $prices['priceVat'];
                    $purchase->items[] = $p;
                }
            }

            $purchase->charges = $this->purchaseStateLoader->getCharges($order);
            $this->appendAfilliateCodes($purchase);

            $dataContainer->ecommerce = $purchase;

            if (!$dataContainer->user) {
                $dataContainer->user = new \stdClass();
            }

            $dataContainer->user->email = $order->invoice_email;

            $userStats = $this->fetchUsersStatsOrderData($order);
            $dataContainer->user->last_order_date = $userStats['last_date'] ?? null;
            $dataContainer->user->first_order_date = $userStats['first_date'] ?? null;
            $dataContainer->user->count_orders = $userStats['count'] ?? null;

            $dataContainer->user->sha_email = hash('sha256',
                $order->invoice_email.($dbcfg->analytics['google_tag_manager']['sha_salt'] ?? false ?: ''));
        }
    }

    /**
     * @return \Decimal
     */
    public function getDeliveryPrice(\Order $order)
    {
        $delivery_item = $this->deliveryInfo->getDeliveryItem($order);

        return $delivery_item ? $order->fetchItems()[$delivery_item]['total_price'] : null;
    }

    protected function appendAfilliateCodes(\stdClass &$purchase)
    {
        $request = $this->getRequest();

        if (!$request) {
            return;
        }

        $cjevent = $request->cookies->get('cjevent') ?: $request->getSession()->get('cjevent');
        if ($cjevent) {
            $purchase->cjevent = $cjevent;
        }

        $AP_tracker_TID = $request->cookies->get('AP_tracker_TID') ?: $request->getSession()->get('AP_tracker_TID');
        if ($AP_tracker_TID) {
            $purchase->AP_tracker_TID = $AP_tracker_TID;
        }
    }

    protected function getRequest(): Request
    {
        return $this->requestStack->getMainRequest();
    }

    public function setPageData($pageData): void
    {
        $this->pageData = $pageData;
    }

    // Až bude košík v twigu, může se smazat
    public function setView(&$view)
    {
    }
}
