<?php

declare(strict_types=1);

namespace KupShop\PreordersBundle\Dto;

use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\KupShopBundle\Arrayable;
use KupShop\KupShopBundle\Util\Price\TotalPrice;
use KupShop\PreordersBundle\Entity\Preorder;
use KupShop\PreordersBundle\Entity\UserPreorder;
use KupShop\PreordersBundle\Service\PreorderUtil;
use KupShop\PreordersBundle\Util\ProductsResult;

class DateDateInfo implements DateInfo, Arrayable, \ArrayAccess
{
    private array $asArray;
    private array $preorderDate;
    private array $validDates;
    private array $validPreorders;

    public function __construct(
        private readonly UserPreorder $userPreorder,
        private readonly ProductsResult $productsAndPrices,
        private readonly PreorderUtil $preorderUtil,
    ) {
    }

    public function getPreorderDate(): array
    {
        return $this->preorderDate ??= $this->userPreorder->getPreorderDate();
    }

    public function getUser(): \User
    {
        return $this->userPreorder->getUser();
    }

    public function getPreorder(): Preorder
    {
        return $this->userPreorder->getPreorder();
    }

    public function getUserPreorder(): UserPreorder
    {
        return $this->userPreorder;
    }

    public function getValidDates(): array
    {
        return $this->validDates ??= $this->preorderUtil->getOpenDates($this->getUser());
    }

    /**
     * @return Preorder[]
     */
    public function getValidPreorders(): array
    {
        if (!isset($this->validPreorders)) {
            $this->validPreorders = [];

            $validPreorderIds = array_unique(array_column($this->getValidDates(), 'id_preorder'));
            // TODO: multifetch Preorders?
            foreach ($validPreorderIds as $id) {
                $this->validPreorders[] = new Preorder($id);
            }
        }

        return $this->validPreorders;
    }

    public function getProducts(): ProductCollection
    {
        return $this->productsAndPrices->products;
    }

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

    public function getTotalBasePrice(): TotalPrice
    {
        return $this->productsAndPrices->totalBasePrice;
    }

    public function isExportAvailable(): bool
    {
        return count($this->userPreorder->getItems()) > 0;
    }

    public function getDiscountLevels(): array
    {
        return $this->getPreorder()->getSettings()['dynamic_prices'] ?? [];
    }

    public function toArray(): array
    {
        return $this->asArray ??= array_merge($this->getPreorderDate(), [
            'dates' => $this->getValidDates(),
            'preorders' => $this->getValidPreorders(),

            'products' => $this->getProducts(),
            'price_total' => $this->getTotalPrice(),
            'base_price_total' => $this->getTotalBasePrice(),

            'export_available' => $this->isExportAvailable(),
            'discount_levels' => $this->getDiscountLevels(),
        ]);
    }

    public function offsetExists(mixed $offset): bool
    {
        return isset($this->toArray()[$offset]);
    }

    public function offsetGet(mixed $offset): mixed
    {
        return $this->toArray()[$offset];
    }

    public function offsetSet(mixed $offset, mixed $value): void
    {
        throw new \LogicException('Not allowed');
    }

    public function offsetUnset(mixed $offset): void
    {
        throw new \LogicException('Not allowed');
    }

    public function getId(): int
    {
        return $this->getUserPreorder()->preorderDateId;
    }

    public function getPiecesSum(): int
    {
        return array_reduce(
            $this->getUserPreorder()->getItems(),
            fn (int $acc, array $item) => $acc + $item['pieces'],
            0,
        );
    }
}
