<?php
/**
 * 2026 Paysera
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * @author Paysera <plugins@paysera.com>
 * @copyright 2026 Paysera
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of Paysera
 */

declare(strict_types=1);

namespace Paysera\PrestashopPayments\Repository;

use Paysera\PrestashopPayments\Factory\PaymentDTOFactory;
use Paysera\PrestashopPayments\Provider\SettingsProvider;
use Paysera\PrestashopPayments\QueryBuilder\PayseraOrdersQueryBuilder;

if (!defined('_PS_VERSION_')) {
    exit;
}

class OrderRepository
{
    public function __construct(
        private SettingsProvider $settingsProvider,
        private PaymentDTOFactory $dtoFactory,
        private PayseraOrdersQueryBuilder $queryBuilder
    ) {
    }

    public function findById(int $orderId): ?\Order
    {
        if ($orderId <= 0) {
            return null;
        }

        $order = new \Order($orderId);

        if (!$order->id) {
            return null;
        }

        return $order;
    }

    public function findByCartId(int $cartId): ?\Order
    {
        $orderId = $this->getOrderIdByCartId($cartId);

        if ($orderId === 0) {
            return null;
        }

        $order = new \Order($orderId);

        if (!$order->id) {
            return null;
        }

        return $order;
    }

    public function hasOrderForCart(int $cartId): bool
    {
        return $this->getOrderIdByCartId($cartId) > 0;
    }

    public function getOrderIdByCartId(int $cartId): int
    {
        return (int) \Order::getIdByCartId($cartId);
    }

    public function findByReference(string $reference): ?\Order
    {
        $orders = \Order::getByReference($reference);

        if ($orders->count() === 0) {
            return null;
        }

        /** @var \Order $order */
        $order = $orders->getFirst();

        return $order;
    }

    /**
     * @return int[]
     */
    public function getStatusHistory(\Order $order): array
    {
        $history = $order->getHistory(0);

        return array_map(
            static fn (array $entry): int => (int) $entry['id_order_state'],
            $history
        );
    }

    public function createFromCart(\Cart $cart, \PayseraPayments $module): int
    {
        $orderStatusId = $this->settingsProvider->getStatusAwaitingPayment();
        $customer = new \Customer($cart->id_customer);

        $module->validateOrder(
            $cart->id,
            $orderStatusId,
            $cart->getOrderTotal(true, \Cart::BOTH),
            $module->displayName,
            null,
            [],
            (int) $cart->id_currency,
            false,
            $customer->secure_key
        );

        return (int) $module->currentOrder;
    }

    /**
     * @param array<string, mixed> $filters
     *
     * @return array{items: array<array<string, mixed>>, totalItems: int, currentPage: int, perPage: int, pages: int}
     */
    public function getPayseraOrders(
        int $page = 1,
        int $perPage = 20,
        string $orderBy = 'date_add',
        string $orderDirection = 'DESC',
        array $filters = []
    ): array {
        $db = \Db::getInstance();

        $builder = $this->queryBuilder
            ->withFilters($filters)
            ->orderBy($orderBy, $orderDirection);

        $totalItems = (int) $db->getValue($builder->buildCountQuery());

        $pages = $totalItems > 0 ? (int) ceil($totalItems / $perPage) : 1;
        $page = max(1, min($page, $pages));

        $rows = $db->executeS(
            $builder->paginate($page, $perPage)->buildSelectQuery()
        );

        $items = [];
        if (is_array($rows)) {
            foreach ($rows as $row) {
                $items[] = $this->dtoFactory->createListItemFromRow($row)->toArray();
            }
        }

        return [
            'items' => $items,
            'totalItems' => $totalItems,
            'currentPage' => $page,
            'perPage' => $perPage,
            'pages' => $pages,
        ];
    }

    public function getPayseraOrderDetails(int $orderId): ?array
    {
        $order = new \Order($orderId);

        if (!$order->id) {
            return null;
        }

        if ($order->module !== 'payserapayments') {
            return null;
        }

        return $this->dtoFactory->createDetailsFromOrder($order)->toArray();
    }
}
