<?php

declare(strict_types=1);

namespace KupShop\ComponentsBundle\Dto;

use KupShop\ComponentsBundle\Contracts\OrderInterface;
use KupShop\ComponentsBundle\Contracts\UserInfoInterface;
use KupShop\KupShopBundle\Util\Price\TotalPrice;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use KupShop\OrderingBundle\Util\Order\OrderItemInfo;
use Query\Operator;

class OrderWrapper implements OrderInterface
{
    private bool $hasProducts;
    private array $items;

    public function __construct(
        private readonly \Order $order,
        private readonly OrderInfo $orderInfo,
        private readonly OrderItemInfo $orderItemInfo,
    ) {
    }

    public function getId(): int
    {
        return $this->order->id;
    }

    public function getTitle(): string
    {
        return str_replace('%ORDERNO', $this->order->order_no, translate('title', 'orderView'));
    }

    public function getUrl(): string
    {
        return path('kupshop_content_orders_order', ['id' => $this->order->id]);
    }

    public function getEditUrl(): string
    {
        return path('kupshop_content_orders_orderedit', ['id' => $this->order->id]);
    }

    public function getOrderNo(): string|int
    {
        return $this->order->order_no;
    }

    public function getDateCreated(): ?\DateTimeInterface
    {
        return $this->order->date_created;
    }

    public function getStatus(): int
    {
        return $this->order->status;
    }

    public function getStatusText(): string
    {
        $order = $this->order;

        if (!isset($order->status_text)) {
            $status = ($order->status_storno == 1 ? 'storno' : $order->status);
            $order->status_text = $this->orderInfo->getOrderStatus($status);
        }

        return $order->status_text;
    }

    public function getTotalPrice(): TotalPrice
    {
        return $this->order->getTotalPrice();
    }

    public function isEditable(): int
    {
        return $this->order->isEditable();
    }

    public function getObject(): object
    {
        return $this->order;
    }

    public function getSource(): string
    {
        return $this->order->source;
    }

    public function hasProducts(): bool
    {
        if (isset($this->hasProducts)) {
            return $this->hasProducts;
        }

        return $this->hasProducts = sqlQueryBuilder()->select('count(*)')
                ->from('order_items', 'oi')
                ->andWhere(Operator::equals(['oi.id_order' => $this->order->id]))
                ->andWhere('oi.id_product IS NOT NULL AND oi.pieces > 0')
                ->execute()->fetchOne() > 0;
    }

    public function getItems(): array
    {
        if (!isset($this->items)) {
            $this->items = [];

            $grouped = [];
            foreach ($this->order->fetchItems() as $key => $item) {
                $item['item_type'] = $this->orderItemInfo->getItemType($item);
                $grouped[$item['item_type']][$key] = $item;

                $this->items[$key] = new OrderItem($item);
            }

            foreach ($grouped[OrderItemInfo::TYPE_CHARGE] ?? [] as $key => $charge) {
                $parentItemId = $charge['note']['charge']['id_item_parent'] ?? null;
                if ($parentItemId && array_key_exists($parentItemId, $this->items)) {
                    $this->items[$parentItemId]['additionalItems'] = new \ArrayObject();
                    $this->items[$parentItemId]['additionalItems'][$key] = $charge;
                    unset($this->items[$key]);
                }
            }

            foreach ($grouped[OrderItemInfo::TYPE_GIFT] ?? [] as $key => $gift) {
                // sety
                $parentItemId = $gift['note']['set_info']['id_parent_item'] ?? null;
                if ($parentItemId && array_key_exists($parentItemId, $this->items)) {
                    $this->items[$parentItemId]['additionalItems'] = new \ArrayObject();
                    $this->items[$parentItemId]['additionalItems'][$key] = $gift;
                    unset($this->items[$key]);
                }
            }
        }

        return $this->items;
    }

    public function getItemsTable(): string
    {
        return $this->order->items_table;
    }

    public function getCurrency(): string
    {
        return $this->order->currency;
    }

    public function getDeliveryUserInfo(): ?UserInfoInterface
    {
        return new OrderDeliveryUserInfo($this->order);
    }

    public function getInvoiceUserInfo(): ?UserInfoInterface
    {
        return new OrderInvoiceUserInfo($this->order);
    }

    public function getHistory(): array
    {
        return $this->order->getHistory();
    }
}
