<?php

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

class OrderInvoiceTaxRepository implements BulkRepositoryInterface
{
    protected \Db $db;

    /**
     * @var array<int, list<array{type: string, rate: float, amount: float}>>
     */
    protected array $byOrderInvoiceCache;

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

    /**
     * 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_invoice: int, type: string, rate: string, amount: string}>|mixed $rows
         */
        $rows = $this->db->executeS(
            'SELECT oi.id_order_invoice, oit.type, oit.amount, t.rate'
            . ' FROM `' . _DB_PREFIX_ . 'order_invoice` oi'
            . ' INNER JOIN `' . _DB_PREFIX_ . 'order_invoice_tax` oit ON oit.id_order_invoice = oi. id_order_invoice'
            . ' INNER JOIN `' . _DB_PREFIX_ . 'tax` t ON t.id_tax = oit.id_tax'
            . ' WHERE oi.id_order IN (' . \implode(',', $orderIds) . ')',
            true,
            false
        );
        if (!\is_array($rows)) {
            throw new \Exception("Can't preload");
        }

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

                $carry[$row['id_order_invoice']][] = [
                    'type' => $row['type'],
                    'rate' => (float) $row['rate'],
                    'amount' => (float) $row['amount'],
                ];

                return $carry;
            },
            []
        );
    }

    /**
     * @return list<array{type: string, rate: float, amount: float}>
     */
    public function getByOrderInvoice(\OrderInvoice $orderInvoice): array
    {
        $id = (int) $orderInvoice->id;

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

        if (null === $ret) {
            $rows = $this->db->executeS(
                'SELECT oi.id_order_invoice, oit.type, oit.amount, t.rate'
                . ' FROM `' . _DB_PREFIX_ . 'order_invoice` oi'
                . ' INNER JOIN `' . _DB_PREFIX_ . 'order_invoice_tax` oit ON oit.id_order_invoice = oi.id_order_invoice'
                . ' INNER JOIN `' . _DB_PREFIX_ . 'tax` t ON t.id_tax = oit.id_tax'
                . ' WHERE oi.id_order_invoice = ' . $id,
                true,
                false
            );

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

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

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

        return $ret;
    }

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