<?php

namespace Myvetshop\Module\Clinique\Accounting\Export\Repository;

class OrderDetailTaxRepository implements BulkRepositoryInterface
{
    protected \Db $db;

    /**
     * @var array<int, list<array{id_order_detail: int, rate: float, amount: float}>>
     */
    protected array $byOrderCache;

    public function __construct(\Db $db)
    {
        $this->db = $db;
        $this->byOrderCache = [];
    }

    /**
     * Preload payment for orders
     *
     * @param \Order[] $orders
     */
    public function preload(array $orders): void
    {
        $orderIds = \array_map(
            fn (\Order $order): int => (int) $order->id,
            $orders
        );

        /**
         * @var list<array{id_order: int, id_order_detail: int, rate: string, amount: string}>|mixed $rows
         */
        $rows = $this->db->executeS(
            'SELECT od.id_order, od.id_order_detail, odt.total_amount AS amount, t.rate'
            . ' FROM `' . _DB_PREFIX_ . 'order_detail` od'
            . ' INNER JOIN `' . _DB_PREFIX_ . 'order_detail_tax` odt ON odt.id_order_detail = od.id_order_detail'
            . ' INNER JOIN `' . _DB_PREFIX_ . 'tax` t ON t.id_tax = odt.id_tax'
            . ' WHERE od.id_order IN (' . \implode(',', $orderIds) . ')',
            true,
            false
        );
        if (!\is_array($rows)) {
            throw new \Exception("Can't preload");
        }

        $this->byOrderCache = \array_reduce(
            $rows,
            function (array $carry, array $row): array {
                if (!isset($carry[$row['id_order']])) {
                    $carry[$row['id_order']] = [];
                }

                $carry[$row['id_order']][(int) $row['id_order_detail']] = [
                    'id_order_detail' => $row['id_order_detail'],
                    'rate' => (float) $row['rate'],
                    'amount' => (float) $row['amount'],
                ];

                return $carry;
            },
            []
        );
    }

    /**
     * @return array<int, array{id_order_detail: int, rate: float, amount: float}>
     */
    public function getByOrder(\Order $order): array
    {
        $id = (int) $order->id;

        $ret = $this->byOrderCache[$id] ?? null;

        if (null === $ret) {
            $rows = $this->db->executeS(
                'SELECT od.id_order, od.id_order_detail, odt.total_amount AS amount, t.rate'
                . ' FROM `' . _DB_PREFIX_ . 'order_detail` od'
                . ' INNER JOIN `' . _DB_PREFIX_ . 'order_detail_tax` odt ON odt.id_order_detail = od.id_order_detail'
                . ' INNER JOIN `' . _DB_PREFIX_ . 'tax` t ON t.id_tax = odt.id_tax'
                . ' WHERE od.id_order = ' . $id,
                true,
                false
            );

            if (!\is_array($rows)) {
                throw new \Exception();
            }

            $ret = \array_reduce(
                $rows,
                function (array $carry, array $row): array {
                    $carry[(int) $row['id_order_detail']] = [
                        'id_order_detail' => $row['id_order_detail'],
                        'rate' => (float) $row['rate'],
                        'amount' => (float) $row['amount'],
                    ];

                    return $carry;
                },
                []
            );
            $this->byOrderCache[$id] = $ret;
        }

        return $ret;
    }

    public function clear(): void
    {
        $this->byOrderCache = [];
    }
}
