<?php

namespace Mnv\Modules\Payment\Payme;

use Mnv\Core\Config;

/**
 * Class Order
 *
 * Example MySQL table might look like to the following:
 *
 * CREATE TABLE orders
 * (
 *     id          INT AUTO_INCREMENT PRIMARY KEY,
 *     product_ids VARCHAR(255)   NOT NULL,
 *     amount      DECIMAL(18, 2) NOT NULL,
 *     state       TINYINT(1)     NOT NULL,
 *     user_id     INT            NOT NULL,
 *     phone       VARCHAR(15)    NOT NULL
 * ) ENGINE = InnoDB;
 *
 */
class PaycomOrder
{

    const STATE_AVAILABLE    = 0; /** Заказ доступен для продажи, его может купить каждый. */
    const STATE_WAITING_PAY  = 1; /** Оплата в процессе, заказ не должен быть изменен. */
    const STATE_PAY_ACCEPTED = 2; /** Заказ завершен и не доступен для продажи. */
    const STATE_CANCELLED    = 3; /** Заказ отменен. */

    const confirmed = 'confirmed'; //подтвердил
    const rejected = 'rejected'; //отвергнуто

    public $request_id;
    public $params;

    /** Adjust Order specific fields for your needs */
    private $_table = 'shop_orders';
    /** Order ID */
    public $order_id;
    /** IDs выбранных товаров / услуг */
//    public $product_ids;
    /** Общая стоимость выбранных товаров / услуг */
    public $amount;
    /** Состояние заказа */
    public $state;
    /** Номер телефона пользователя */
//    public $phone;


    public function __construct($request_id)
    {
        $this->request_id = $request_id;
    }

    /**
     * Проверяет сумму и значения счета.
     * @param array $params amount and account parameters to validate.
     * @return bool true - if validation passes
     * @throws PaycomException - if validation fails
     */
    public function validate(array $params)
    {
        /** Проверка суммы, если, например, произошел сбой при ошибке, сумме проверках числовая */
        if (!is_numeric($params['amount'])) {
            throw new PaycomException( $this->request_id, 'Incorrect amount.', PaycomException::ERROR_INVALID_AMOUNT); // 'Неверная сумма.',-31001
        }

        /** Подтвердите аккаунт, если предполагается, что произошел сбой при броске, у нас должен быть order_id */
        if (!isset($params['account']['order_id']) || !$params['account']['order_id']) {
            throw new PaycomException($this->request_id, PaycomApplication::message('Неверный код заказа.', 'Harid kodida xatolik.', 'Incorrect order code.'),
                PaycomException::ERROR_INVALID_ACCOUNT, //-31050,
                'order_id'
            );
        }

        /** Проверьте, доступен ли заказ */
        // предположим, после find() $this это будет заполнено данными Order
        $order = $this->find($params['account']);

        // Проверьте, найден ли заказ по указанному идентификатору order_id
        if (!$order || !$order->order_id) {
            throw new PaycomException($this->request_id, PaycomApplication::message('Неверный код заказа.', 'Harid kodida xatolik.', 'Incorrect order code.'),
                PaycomException::ERROR_INVALID_ACCOUNT, //-31050,
                'order_id'
            );
        }

        // подтвердить сумму
        // convert $this->amount to coins
        // $params['amount'] already in coins
        if ((100 * $this->amount) != (1 * $params['amount'])) {
            throw new PaycomException($this->request_id, 'Incorrect amount.', PaycomException::ERROR_INVALID_AMOUNT); // 'Неверная сумма.', -31001
        }

        // например, состояние заказа до оплаты должно быть «ожидание оплаты»
        if ($this->state != self::STATE_WAITING_PAY) { // 1
            throw new PaycomException($this->request_id, 'Order state is invalid.', PaycomException::ERROR_COULD_NOT_PERFORM); // 'Состояние заказа недействительно.', -31008
        }

        // сохранить параметры для дальнейшего использования
        $this->params = $params;

        return true;
    }

    /**
     * Найти порядок по заданным параметрам.
     *
     * @param mixed $params parameters.
     * @return PaycomOrder|PaycomOrder[] found order or array of orders.
     */
    public function find($params)
    {
        /** Реализация порядка (ов) поиска по заданным параметрам, заполнение текущего экземпляра данными */
        // Пример реализации для загрузки заказа по идентификатору
        if (isset($params['order_id'])) {
            if ($result = connect($this->_table)->select('order_id, amount, state')->where('order_id', $params['order_id'])->get()) {
                $this->order_id = 1 * $result->order_id;
                $this->amount   = 1 * $result->amount;
                $this->state    = 1 * $result->state;

                return $this;
            }
        }

        return null;
    }

    /**
     * Изменить состояние заказа на указанное.
     * @param int $state new state of the order
     * @throws PaycomException
     */
    public function changeState($state)
    {
        /** Реализовать изменение состояния заказа (резервный заказ после создания транзакции или свободный заказ после отмены) */
        $this->state = 1 * $state;
        $this->save();
    }

    /**
     *Проверьте, можно ли отменить заказ или нет.
     * @return bool true - заказ отменяется, в противном случае ложный.
     */
    public function allowCancel()
    {
        /** Реализация проверки отмены заказа */
        return true; // do not allow cancellation
    }

    /**
     * Сохраняет этот заказ.
     * @throws PaycomException
     */
    public function save()
    {
        if (!$this->order_id) {
            // Если новый заказ, установите его состояние ожидания
            $result['amount']   = $this->amount;
            $result['state']    = PaycomOrder::STATE_WAITING_PAY; // 1

            if ($is_success = connect($this->_table)->insert($result)) {
                $this->order_id = $is_success;
            }
        } else {
            if ($this->state == PaycomOrder::STATE_PAY_ACCEPTED) {
                $updateOrder['status'] = PaycomOrder::confirmed;
            } elseif ($this->state == PaycomOrder::STATE_CANCELLED) {
                $updateOrder['status'] = PaycomOrder::rejected;
            }
            $updateOrder['state'] = $this->state;
            $is_success = connect($this->_table)->where('order_id', $this->order_id)->update($updateOrder);

            if ($this->state == PaycomOrder::STATE_PAY_ACCEPTED) {
                $this->updateUserPaid();
            }

        }

        if ($is_success == -1) {
            throw new PaycomException($this->request_id, 'Could not save order.', PaycomException::ERROR_INTERNAL_SYSTEM);
        }
    }

    private function updateUserPaid(): void
    {
        if (!empty($this->order_id)) {
            $order['start_date'] = gmdate('Y-m-d H:i:s');
            $order['end_date']   = date('Y-m-d H:i:s', strtotime($order['start_date'] . "+365 days"));

            connect('user_membership')->where('orderId', $this->order_id)->update([
                'start_date'            => $order['start_date'],
                'end_date'              => $order['end_date'],
                'status'                => $this->state,
            ]);
        }
    }

    /** Детализация для фискального чека */
    public function getDetail(array $params): array
    {

        // В объекте additional биллинг поставщика может возвращать дополнительную информацию (баланс пользователя, данные о заказе)
        // Кроме того, добавляя объект additional, следует сообщить об этом техническому специалисту Payme Business.
//        $detail["additional"] = [
//            "field_name" => "field_value"
//        ];

        $order = connect($this->_table)->select('order_id, address, shipping_amount')->where('order_id', $params['order_id'])->get('array');

        $detail['receipt_type'] = 0; // тип фискального чека Продажа/Возврат = 0
        $detail['shipping'] = [ // доставка, необязательное поле
            'title' => $order['address'],
            'price' => round(1 * $order['shipping_amount'] * 100)
        ];
        $detail['items'] = [];
        if (isset($params['order_id'])) {
            if ($products = connect('shop_order_product')->select('order_id, product_id, name, brand, quantity, price, total')->where('order_id', $params['order_id'])->getAll('array')) {
                $items = [];
                collect($products)->map(function ($item, $index) use (&$items) {
//                    $item['price'] = (int)$item['price'] . '00';
                    $infoProduct = connect('products')->select('productId, title, ikpu, units')->where('productId', $item['product_id'])->get('array');

                    $items[$index]['discount'] = 0;                             // optional  Скидка с учетом количества товаров или услуг в тийинах
                    $items[$index]['title']         = $infoProduct['title'];    // наименование товара или услуги
                    $items[$index]['price']         = round(1 * $item['price'] * 100);      // цена за единицу товара или услуги, сумма указана в тийинах
                    $items[$index]['count']         = (int)$item['quantity'];   // кол-во товаров или услуг
                    $items[$index]['code']          = $infoProduct['ikpu'];     // код *ИКПУ обязательное поле
//                    $items[$index]['units']         = 0;                        // optional значение изменится в зависимости от вида товара
                    $items[$index]['vat_percent']   = 12;                       // обязательное поле, процент уплачиваемого НДС для данного товара или услуги
                    $items[$index]['package_code']  = $infoProduct['units'];    // Код упаковки для конкретного товара или услуги, содержится на сайте в деталях найденного ИКПУ.

                })->all();

                $detail['items'] = $items;

                return $detail;
            }
        }

        return  $detail;
    }



}
