<commit_before><?php
/**
 * Steam.php
 * Copyright (c) 2019 <EMAIL>
 *
 * This file is part of Firefly III (https://github.com/firefly-iii).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
declare(strict_types=1);

namespace FireflyIII\Support;

use Carbon\Carbon;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
use stdClass;

/**
 * Class Steam.
 * @codeCoverageIgnore
 */
class Steam
{

    /**
     * @param \FireflyIII\Models\Account $account
     * @param \Carbon\Carbon             $date
     *
     * @return string
     */
    public function balance(Account $account, Carbon $date): string
    {
        if ('testing' === config('app.env')) {
            Log::warning(sprintf('%s should NOT be called in the TEST environment!', __METHOD__));
        }
        // abuse chart properties:
        $cache = new CacheProperties;
        $cache->addProperty($account->id);
        $cache->addProperty('balance');
        $cache->addProperty($date);
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }
        /** @var AccountRepositoryInterface $repository */
        $repository = app(AccountRepositoryInterface::class);
        $currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUser($account->user);

        // first part: get all balances in own currency:
        $nativeBalance = (string)$account->transactions()
                                         ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                         ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
                                         ->where('transactions.transaction_currency_id', $currency->id)
                                         ->sum('transactions.amount');

        // get all balances in foreign currency:
        $foreignBalance = (string)$account->transactions()
                                          ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                          ->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
                                          ->where('transactions.foreign_currency_id', $currency->id)
                                          ->where('transactions.transaction_currency_id', '!=', $currency->id)
                                          ->sum('transactions.foreign_amount');

        // check:
        Log::debug(sprintf('Steam::balance. Native balance is "%s"', $nativeBalance));
        Log::debug(sprintf('Steam::balance. Foreign balance is "%s"', $foreignBalance));

        $balance = bcadd($nativeBalance, $foreignBalance);
        $virtual = null === $account->virtual_balance ? '0' : (string)$account->virtual_balance;

        Log::debug(sprintf('Steam::balance. Virtual balance is "%s"', $virtual));

        $balance = bcadd($balance, $virtual);
        $cache->store($balance);

        return $balance;
    }

    /**
     * @param \FireflyIII\Models\Account $account
     * @param \Carbon\Carbon             $date
     *
     * @return string
     */
    public function balanceIgnoreVirtual(Account $account, Carbon $date): string
    {
        if ('testing' === config('app.env')) {
            Log::warning(sprintf('%s should NOT be called in the TEST environment!', __METHOD__));
        }
        // abuse chart properties:
        $cache = new CacheProperties;
        $cache->addProperty($account->id);
        $cache->addProperty('balance-no-virtual');
        $cache->addProperty($date);
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }
        /** @var AccountRepositoryInterface $repository */
        $repository = app(AccountRepositoryInterface::class);
        $repository->setUser($account->user);

        $currencyId    = (int)$repository->getMetaValue($account, 'currency_id');
        $nativeBalance = (string)$account->transactions()
                                         ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                         ->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
                                         ->where('transactions.transaction_currency_id', $currencyId)
                                         ->sum('transactions.amount');

        // get all balances in foreign currency:
        $foreignBalance = (string)$account->transactions()
                                          ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                          ->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
                                          ->where('transactions.foreign_currency_id', $currencyId)
                                          ->where('transactions.transaction_currency_id', '!=', $currencyId)
                                          ->sum('transactions.foreign_amount');
        $balance        = bcadd($nativeBalance, $foreignBalance);

        $cache->store($balance);

        return $balance;
    }

    /**
     * Gets the balance for the given account during the whole range, using this format:.
     *<commit_msg>Fix #3154<commit_after><?php
/**
 * Steam.php
 * Copyright (c) 2019 <EMAIL>
 *
 * This file is part of Firefly III (https://github.com/firefly-iii).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
declare(strict_types=1);

namespace FireflyIII\Support;

use Carbon\Carbon;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
use stdClass;

/**
 * Class Steam.
 * @codeCoverageIgnore
 */
class Steam
{

    /**
     * @param \FireflyIII\Models\Account $account
     * @param \Carbon\Carbon             $date
     *
     * @return string
     */
    public function balance(Account $account, Carbon $date): string
    {
        if ('testing' === config('app.env')) {
            Log::warning(sprintf('%s should NOT be called in the TEST environment!', __METHOD__));
        }
        // abuse chart properties:
        $cache = new CacheProperties;
        $cache->addProperty($account->id);
        $cache->addProperty('balance');
        $cache->addProperty($date);
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }
        /** @var AccountRepositoryInterface $repository */
        $repository = app(AccountRepositoryInterface::class);
        $currency   = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUser($account->user);

        // first part: get all balances in own currency:
        $transactions  = $account->transactions()
                                 ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                 ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
                                 ->where('transactions.transaction_currency_id', $currency->id)
                                 ->get(['transactions.amount'])->toArray();
        $nativeBalance = $this->sumTransactions($transactions, 'amount');

        // get all balances in foreign currency:
        $transactions   = $account->transactions()
                                  ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                  ->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
                                  ->where('transactions.foreign_currency_id', $currency->id)
                                  ->where('transactions.transaction_currency_id', '!=', $currency->id)
                                  ->get(['transactions.foreign_amount'])->toArray();
        $foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');

        // check:
        Log::debug(sprintf('Steam::balance. Native balance is "%s"', $nativeBalance));
        Log::debug(sprintf('Steam::balance. Foreign balance is "%s"', $foreignBalance));

        $balance = bcadd($nativeBalance, $foreignBalance);
        $virtual = null === $account->virtual_balance ? '0' : (string)$account->virtual_balance;

        Log::debug(sprintf('Steam::balance. Virtual balance is "%s"', $virtual));

        $balance = bcadd($balance, $virtual);

        $cache->store($balance);

        return $balance;
    }

    /**
     * @param \FireflyIII\Models\Account $account
     * @param \Carbon\Carbon             $date
     *
     * @return string
     */
    public function balanceIgnoreVirtual(Account $account, Carbon $date): string
    {
        if ('testing' === config('app.env')) {
            Log::warning(sprintf('%s should NOT be called in the TEST environment!', __METHOD__));
        }
        // abuse chart properties:
        $cache = new CacheProperties;
        $cache->addProperty($account->id);
        $cache->addProperty('balance-no-virtual');
        $cache->addProperty($date);
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }
        /** @var AccountRepositoryInterface $repository */
        $repository = app(AccountRepositoryInterface::class);
        $repository->setUser($account->user);

        $currencyId = (int)$repository->getMetaValue($account, 'currency_id');


        $transactions  = $account->transactions()
                                 ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                 ->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
                                 ->where('transactions.transaction_currency_id', $currencyId)
                                 ->get(['transactions.amount'])->toArray();
        $nativeBalance = $this->sumTransactions($transactions, 'amount');

        // get all balances in foreign currency:
        $transactions = $account->transactions()
                                ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
                                ->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
                                ->where('transactions.foreign_currency_id', $currencyId)
                                ->where('transactions.transaction_currency_id', '!=', $currencyId)
                                ->get(['transactions.foreign_amount'])->toArray();

        $foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');
        $balance        = bcadd($nativeBalance, $foreignBalance);

        $cache->store($balance);

        return $balance;
    }

    /**
     * @param array  $transactions
     * @param string $key
     *
     * @return string
     */
    public function sumTransactions(array $transactions, string $key): string
    {
        $sum = '0';
        /** @var array $transaction */
        foreach ($transactions as $transaction) {
            $sum = bcadd($sum, $transaction[$key] ?? '0');
        }

        return $sum;
    }

    /**
     * Gets the balance for the given account during the whole range, using this format:.
     *
{'fraction_non_alphanumeric': 0.13509727626459145, 'fraction_numerical': 0.002490272373540856, 'mean_word_length': 2.2850204498977504, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 117, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 49, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7280555', 'n_tokens_mistral': 3278, 'n_tokens_neox': 3187, 'n_words': 761}