<?php

/**
 * Copyright © Resurs Bank AB. All rights reserved.
 * See LICENSE for license details.
 */

declare(strict_types=1);

namespace Resursbank\MerchantApi\Repository;

use Db;
use Order;
use PrestaShopDatabaseException;
use PrestaShopException;
use Resursbank\Ecom\Exception\Validation\IllegalValueException;
use Resursbank\Ecom\Lib\Model\Payment;
use Resursbank\Ecom\Lib\Validation\StringValidation;
use Resursbank\MerchantApi\Entity\ResursbankOrder;
use Resursbank\MerchantApi\Exception\InvalidArgumentException;
use Resursbank\MerchantApi\Service\Database;
use Validate;

class ResursbankOrderRepositoryFrontend
{
    public const TABLE_NAME = _DB_PREFIX_ . 'resursbank_order';

    /**
     * Return PrestaShop order object from MAPI ID.
     *
     * @throws InvalidArgumentException
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     * @throws IllegalValueException
     */
    public static function getOrderByMapiId(string $mapiId): ?Order
    {
        if (!(new StringValidation())->isUuid($mapiId)) {
            throw new InvalidArgumentException('Mapi id is not a valid UUID');
        }

        $query = 'SELECT * FROM ' . self::TABLE_NAME . ' WHERE mapi_id = "' . $mapiId . '"';
        $entry = self::find(query: $query);

        if (!is_null($entry)) {
            $order = new Order($entry->getOrderId());

            if (Validate::isLoadedObject($order)) {
                return $order;
            }
        }

        return null;
    }

    /**
     * Resolve resursbank_order from mapi_id value.
     *
     * @param string $mapiId
     * @return ResursbankOrder
     * @throws InvalidArgumentException
     * @throws PrestaShopDatabaseException
     */
    public static function findByMapiId(
        string $mapiId
    ): ResursbankOrder {
        // Use Db to resolve data from resursbank_order table.
        $sql = 'SELECT * FROM ' . self::TABLE_NAME . " WHERE mapi_id = '$mapiId'";
        $data = Database::getAll(result: Db::getInstance()->query($sql));

        // There should be only 1 entry.
        if (count($data) !== 1) {
            throw new InvalidArgumentException('Invalid number of entries found');
        }

        // Convert first data entry to ResursbankOrder.
        $order = new ResursbankOrder();

        $order->setId((int) $data[0]['id']);
        $order->setOrderId((int) $data[0]['order_id']);
        $order->setTest((bool) $data[0]['test']);
        $order->setReadyForCallback((bool) $data[0]['ready_for_callback']);
        $order->setMapiId($data[0]['mapi_id'] ?? null);

        return $order;
    }

    /**
     * Resolve resursbank_order from PrestaShop Order ID.
     *
     * @param int $orderId
     * @return ResursbankOrder
     * @throws InvalidArgumentException
     * @throws PrestaShopDatabaseException
     */
    public static function findByOrderId(
        int $orderId
    ): ResursbankOrder {
        // Use Db to resolve data from resursbank_order table.
        $sql = 'SELECT * FROM ' . self::TABLE_NAME . " WHERE order_id = '$orderId'";
        $data = Database::getAll(result: Db::getInstance()->query($sql));

        // There should be only 1 entry.
        if (count($data) !== 1) {
            throw new InvalidArgumentException('Invalid number of entries found');
        }

        // Convert first data entry to ResursbankOrder.
        $order = new ResursbankOrder();

        $order->setId((int) $data[0]['id']);
        $order->setOrderId((int) $data[0]['order_id']);
        $order->setTest((bool) $data[0]['test']);
        $order->setReadyForCallback((bool) $data[0]['ready_for_callback']);
        $order->setMapiId($data[0]['mapi_id'] ?? null);

        return $order;
    }

    /**
     * @throws PrestaShopDatabaseException
     */
    private static function find(string $query): ?ResursbankOrder
    {
        $result = Database::getAll(result: Db::getInstance()->query($query));

        foreach ($result as $row) {
            $order = new ResursbankOrder();
            $order->setId((int) $row['id']);
            $order->setOrderId((int) $row['order_id']);
            $order->setTest((bool) $row['test']);
            $order->setReadyForCallback((bool) $row['ready_for_callback']);
            $order->setMapiId($row['mapi_id'] ?? null);

            return $order;
        }

        return null;
    }

    /**
     * Create a new record in the table.
     *
     * @param Order $order the order entity to insert
     * @param Payment $payment payment at Resurs Bank
     * @param bool $test whether purchase was made with test API environment
     * @param bool $readyForCallback whether associated order accepts callbacks
     *
     * @return bool true on success, false on failure
     */
    public static function createMapiRecord(
        Order $order,
        Payment $payment,
        bool $test,
        bool $readyForCallback
    ): bool {
        $orderId = (int) $order->id;
        $testValue = $test ? 1 : 0;
        $rdy = $readyForCallback ? 1 : 0;
        $mapiId = $payment->id;

        $sql = 'INSERT INTO ' . self::TABLE_NAME .
            " (order_id, test, ready_for_callback, mapi_id) VALUES ($orderId, $testValue, $rdy, '$mapiId')";

        return Db::getInstance()->execute($sql);
    }
}
