<?php

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

class OrderPaymentRepository implements BulkRepositoryInterface
{
    protected \Db $db;

    /**
     * @var array<int, \OrderPayment[]>
     */
    protected array $byOrderCache;

    /**
     * @var array<int, \OrderPayment[]>
     */
    protected array $byOrderInvoiceCache;

    public function __construct(\Db $db)
    {
        $this->db = $db;
        $this->byOrderCache = [];
        $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
        );

        $rows = $this->db
            ->executeS(
                'SELECT poip.id_order_invoice, poip.id_order, pop.*'
                . ' FROM `' . _DB_PREFIX_ . 'order_invoice_payment` poip'
                . ' INNER JOIN `' . _DB_PREFIX_ . 'order_payment` pop ON pop.id_order_payment = poip.id_order_payment'
                . ' WHERE poip.id_order IN (' . implode(',', $orderIds) . ')',
                true,
                false
            );

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

        foreach ($rows as $row) {
            $idOrder = (int) $row['id_order'];
            $idOrderInvoice = (int) $row['id_order_invoice'];

            if (!isset($this->byOrderCache[$idOrder])) {
                $this->byOrderCache[$idOrder] = [];
            }
            if (!isset($this->byOrderInvoiceCache[$idOrderInvoice])) {
                $this->byOrderInvoiceCache[$idOrderInvoice] = [];
            }

            $orderPayment = new \OrderPayment();
            $orderPayment->hydrate($row);

            $this->byOrderCache[$idOrder][] = $orderPayment;
            $this->byOrderInvoiceCache[$idOrderInvoice][] = $orderPayment;
        }
    }

    /**
     * @return \OrderPayment[]
     */
    public function getByOrderInvoice(\OrderInvoice $orderInvoice): array
    {
        $payments = $this->byOrderInvoiceCache[(int) $orderInvoice->id] ?? null;

        if (null === $payments) {
            $rows = $this->db
                ->executeS(
                    'SELECT pop.* FROM `' . _DB_PREFIX_ . 'order_invoice_payment` poip'
                    . ' INNER JOIN `' . _DB_PREFIX_ . 'order_payment` pop ON pop.id_order_payment = poip.id_order_payment'
                    . ' WHERE poip.id_order_invoice = ' . (int) $orderInvoice->id,
                    true,
                    false
                );

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

            /** @var \OrderPayment[] $payments */
            $payments = \ObjectModel::hydrateCollection(\OrderPayment::class, $rows);

            $this->byOrderInvoiceCache[(int) $orderInvoice->id] = $payments;
        }

        return $payments;
    }

    /**
     * @return \OrderPayment[]
     */
    public function getByOrder(\Order $order): array
    {
        $payments = $this->byOrderCache[(int) $order->id] ?? null;

        if (null === $payments) {
            $rows = $this->db
                ->executeS(
                    'SELECT *'
                    . ' FROM `' . _DB_PREFIX_ . 'order_payment`'
                    . ' WHERE order_reference = "' . $this->db->escape($order->reference) . '"',
                    true,
                    false
                );

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

            /** @var \OrderPayment[] $payments */
            $payments = \ObjectModel::hydrateCollection(\OrderPayment::class, $rows);

            $this->byOrderCache[(int) $order->id] = $payments;
        }

        return $payments;
    }

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