<?php
/**
 * Author: lopiu
 * Date: 03.07.2020
 * Time: 07:24
 */

class Bank
{
    public $user_id;
    public $money;
    private $user;

    const ERROR_NO_MONEY_IN_WALLET = "Ошибка! Нет денег в кошельке!";
    const ERROR_NO_BANK_ACCOUNT = "Ошибка! Счёта не существует!";
    const ERROR_NO_MONEY_IN_BANK_ACCOUNT = "Ошибка! Нет денег на счету!";
    const ERROR_WRONG_AMOUNT = "Ошибка! Сумма должна быть положительной!";
    const LOG_SEND = "Банк: Перевод средств на другой счёт.";
    const LOG_RECEIVE = "Банк: Получение средств.";
    const LOG_DEPOSIT = "Пополнение счёта.";
    const LOG_WITHDRAW = "Снятие денег со счёта.";

    public function __construct($row)
    {
        $bank_row = db::c()->query('SELECT user_id, money FROM bank WHERE user_id = ?i', $row)->fetch_assoc();
        $this->user = db::c()->query('SELECT money FROM users WHERE id = ?i', $row)->fetch_object();
        foreach ($this as $key => $value) {
            if (isset($bank_row[$key])) {
                $this->$key = $bank_row[$key];
            }
        }
        // Если ВДРУГ у человека нет счёта в банке - создаём.
        if (empty($this->user_id)) {
            db::c()->query('INSERT INTO bank (user_id) VALUES (?i)', $row);
            $this->user_id = $row;
        }
    }

    /**
     * Комиссия: self::BANK_COMISSION от переводимой суммы, но не менее 1 кр.
     *
     * @param $amount
     *
     * @return int
     */
    private function bankComission($amount)
    {
        $bankComission = round($amount * Config::$bank_comission);
        if ($bankComission < 1) {
            return 1;
        } else {
            return (int)$bankComission;
        }
    }

    /**
     * Пишем банковское событие в лог в БД
     *
     * @param int $receiverId - user_id получателя
     * @param int $amount
     * @param string $operationType
     * @param int $senderId
     *
     * @throws \Krugozor\Database\Mysql\Exception
     */
    private function bankLogs(int $receiverId, int $amount, string $operationType, int $senderId = 0)
    {
        if (!$senderId) {
            $senderId = $this->user_id;
        }
        $text = '';
        if ($operationType === "sendMoney") {
            $text = self::LOG_SEND . " Комиссия: " . $this->bankComission($amount);
        } elseif ($operationType === "depositMoney") {
            $receiverId = $this->user_id;
            $text = self::LOG_DEPOSIT;
        } elseif ($operationType === "withdrawMoney") {
            $receiverId = $this->user_id;
            $text = self::LOG_WITHDRAW . " Комиссия: " . $this->bankComission($amount);
        }

        db::c()->query('INSERT INTO `bank_logs` (sender_id, receiver_id, amount_result, type, text) 
                            VALUES (?i, ?i, ?i, "?s", "?s")', $senderId, $receiverId, $amount, $operationType, $text);

    }

    /**
     * Перевод денег между бансковскими счетами игроков с банковской комиссией.
     *
     * @param int $receiver
     * @param int $amount
     *
     * @return void
     * @throws \Krugozor\Database\Mysql\Exception
     */
    public function sendMoney(int $receiver, int $amount): void
    {
        $receiverWallet = db::c()->query('SELECT money FROM bank WHERE user_id = ?i', $receiver)->fetch_object();
        if ($amount <= 0) {
            throw new Exception(self::ERROR_WRONG_AMOUNT);
        }
        if (!$receiverWallet) {
            throw new Exception(self::ERROR_NO_BANK_ACCOUNT);
        }
        $amountWithComission = $amount + $this->bankComission($amount);
        if ($amountWithComission > $this->money) {
            throw new Exception(self::ERROR_NO_MONEY_IN_BANK_ACCOUNT);
        }
        // Снимаем сумму с комиссией у отправителя
        $this->money -= $amountWithComission;
        self::setBankMoney($this->money, $this->user_id);
        $this->bankLogs($receiver, $this->money, "sendMoney");
        // Отдаём сумму на счёт получателю
        $receiverWallet->money += $amount;
        self::setBankMoney($receiverWallet->money, $receiver);
        $this->bankLogs($receiver, $receiverWallet->money, "receiveMoney");
    }

    /**
     * Пополнение банковского счёта игрока
     *
     * @param int $amount - сумма
     *
     * @return void
     * @throws \Krugozor\Database\Mysql\Exception
     */
    public function depositMoney(int $amount): void
    {
        if ($amount <= 0) {
            throw new Exception(self::ERROR_WRONG_AMOUNT);
        }
        $wallet = db::c()->query('SELECT money FROM users WHERE id = ?i', $this->user_id)->fetch_object();
        if ($wallet->money < $amount) {
            throw new Exception(self::ERROR_NO_MONEY_IN_WALLET);
        }
        // Забираем деньги из кошелька получателя
        //todo check it!
        $this->user->money -= $amount;
        self::setWalletMoney($this->user->money, $this->user_id);
        // Отдаём сумму на счёт получателю
        $this->money += $amount;
        self::setBankMoney($this->money, $this->user_id);
        $this->bankLogs(0, $this->money, "depositMoney");
    }

    /**
     * Снятие денег с банковского счёта игрока с банковской комиссией.
     *
     * @param int $amount - сумма
     *
     * @return void
     * @throws \Krugozor\Database\Mysql\Exception
     */
    public function withdrawMoney(int $amount): void
    {
        if ($amount <= 0) {
            throw new Exception(self::ERROR_WRONG_AMOUNT);
        }
        $amountWithComission = $amount + $this->bankComission($amount);
        if ($this->money < $amountWithComission) {
            throw new Exception(self::ERROR_NO_MONEY_IN_BANK_ACCOUNT);
        }
        // Снимаем сумму с комиссией у отправителя
        $this->money -= $amountWithComission;
        self::setBankMoney($this->money, $this->user_id);
        $this->bankLogs(0, $this->money, "withdrawMoney");
        // Отдаём сумму в кошелёк получателя
        //todo check it!
        $this->user->money += $amount;
        self::setWalletMoney($this->user->money, $this->user_id);
    }

    /**
     * Установить количество денег на банковском счету.
     *
     * @param int $amount сумма.
     * @param int $user_id ID пользователя.
     * @param string $operationType Тип операции. По умолчанию пусто. Если ввести, система запишет событие в банковский лог.
     *
     * @throws \Krugozor\Database\Mysql\Exception
     */
    public static function setBankMoney(int $amount, int $user_id, string $operationType = ''): void
    {
        db::c()->query('UPDATE bank SET money = ?i WHERE user_id = ?i', $amount, $user_id);
        if ($operationType) {
            (new Bank($user_id))->bankLogs(0, $amount, $operationType);
        }
    }

    /**
     * Установить количество денег на руках.
     *
     * @param int $amount - сумма.
     * @param int $user_id - ID пользователя.
     *
     * @throws \Krugozor\Database\Mysql\Exception
     */
    public static function setWalletMoney(int $amount, int $user_id): void
    {
        db::c()->query('UPDATE users SET money = ?i WHERE `id` = ?i', $amount, $user_id);
    }

    public function getBankMoney() {
        return $this->money;
    }
}