<commit_before><?php

namespace FireflyIII\Repositories\Account;

use Auth;
use Carbon\Carbon;
use Config;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
use Session;
use Steam;


/**
 * @SuppressWarnings(PHPMD.TooManyMethods)
 *
 * Class AccountRepository
 *
 * @package FireflyIII\Repositories\Account
 */
class AccountRepository implements AccountRepositoryInterface
{

    /**
     * @param array $types
     *
     * @return int
     */
    public function countAccounts(array $types)
    {
        return Auth::user()->accounts()->accountTypeIn($types)->count();
    }

    /**
     * @param Account $account
     *
     * @return boolean
     */
    public function destroy(Account $account)
    {
        $account->delete();

        return true;
    }

    /**
     * @param array $types
     *
     * @return Collection
     */
    public function getAccounts(array $types)
    {
        /** @var Collection $result */
        $result = Auth::user()->accounts()->with(
            ['accountmeta' => function (HasMany $query) {
                $query->where('name', 'accountRole');
            }]
        )->accountTypeIn($types)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);

        $result = $result->sortBy(
            function (Account $account) {
                return strtolower($account->name);
            }
        );

        return $result;
    }


    /**
     * @return Collection
     */
    public function getCreditCards()
    {
        return Auth::user()->accounts()
                   ->hasMetaValue('accountRole', 'ccAsset')
                   ->hasMetaValue('ccType', 'monthlyFull')
                   ->get(
                       [
                           'accounts.*',
                           'ccType.data as ccType',
                           'accountRole.data as accountRole'
                       ]
                   );
    }

    /**
     * @param TransactionJournal $journal
     * @param Account            $account
     *
     * @return Transaction
     */
    public function getFirstTransaction(TransactionJournal $journal, Account $account)
    {

        return $journal->transactions()->where('account_id', $account->id)->first();
    }

    /**
     * @param Preference $preference
     *
     * @return Collection
     */
    public function getFrontpageAccounts(Preference $preference)
    {
        $cache = new CacheProperties();
        $cache->addProperty($preference->data);
        $cache->addProperty('frontPageaccounts');
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }


        if ($preference->data == []) {
            $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
        } else {
            $accounts = Auth::user()->accounts()->whereIn('id', $preference->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
        }

        $cache->store($accounts);

        return $accounts;
    }

    /**
     * This method is used on the front page where (in turn) its viewed journals-tiny.php which (in turn)
     * is almost the only place where formatJournal is used. Aka, we can use some custom querying to get some specific.
     * fields using left joins.
     *
     * @param Account $account
     * @param Carbon  $start
     * @param Carbon  $end
     *
     * @return mixed
     */
    public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
    {
        $cache = new CacheProperties();
        $cache->addProperty($account->id);
        $cache->addProperty($start);
        $cache->addProperty($end);
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }

        $set = Auth::user()
                   ->transactionjournals()
                   ->with(['transactions'])
                   ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
                   ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
                   ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id')
                   ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
                   ->before($end)
                   ->after($start)
                   ->orderBy('transaction_journals.date', 'DESC')
                   ->orderBy('transaction_journals.id', 'DESC')
                   ->take(10)
                   ->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
        $cache->store($set);

        return $set;
    }

    /**
     * @param Account $account
     * @param int     $page
     *
     * @return LengthAwarePaginator
     */
    public function getJournals(Account $account, $page)
    {
        $offset = ($page - 1) * 50;
        $query  = Auth::user()
                      ->transactionJournals()
                      ->withRelevantData()
                      ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
                      ->where('transactions.account_id', $account->id)
                      ->orderBy('transaction_journals.date', 'DESC')
                      ->orderBy('transaction_journals.order', 'ASC')
                      ->orderBy('transaction_journals.id', 'DESC');

        $count     = $query->count();
        $set       = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
        $paginator = new LengthAwarePaginator($set, $count, 50, $page);

        return $paginator;


    }

    /**
     * @param Account $account
     *
     * @return Carbon|null
     */
    public function getLastActivity(Account $account)
    {
        $lastTransaction = $account->transactions()->leftJoin(
            'transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
        )->orderBy('transaction_journals.date', 'DESC')->first(['transactions.*', 'transaction_journals.date']);
        if ($lastTransaction) {
            return $lastTransaction->transactionjournal->date;
        }

        return null;
    }

    /**
     * Get the accounts of a user that have piggy banks connected to them.
     *
     * @return Collection
     */
    public function getPiggyBankAccounts()
    {
        $ids        = [];
        $start      = clone Session::get('start', new Carbon);
        $end        = clone Session::get('end', new Carbon);
        $accountIds = DB::table('piggy_banks')->distinct()->get(['piggy_banks.account_id']);
        $accounts   = new Collection;

        /** @var PiggyBank $id */
        foreach ($accountIds as $id) {
            $ids[] = intval($id->account_id);
        }

        $cache = new CacheProperties;
        $cache->addProperty($ids);
        $cache->addProperty('piggyAccounts');
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }

        $ids = array_unique($ids);
        if (count($ids) > 0) {
            $accounts = Auth::user()->accounts()->whereIn('id', $ids)->get();
        }

        $accounts->each(
            function (Account $account) use ($start, $end) {
                $account->startBalance = Steam::balance($account, $start, true);
                $account->endBalance   = Steam::balance($account, $end, true);
                $account->piggyBalance = 0;
                /** @var PiggyBank $piggyBank */
                foreach ($account->piggyBanks as $piggyBank) {
                    $account->piggyBalance += $piggyBank->currentRelevantRep()->currentamount;
                }
                // sum of piggy bank amounts on this account:
                // diff between endBalance and piggyBalance.
                // then, percentage.
                $difference          = $account->endBalance - $account->piggyBalance;
                $account->difference = $difference;
                $account->percentage = $difference != 0 && $account->endBalance != 0 ? round((($difference / $account->endBalance) * 100)) : 100;

            }
        );

        $cache->store($accounts);

        return $accounts;

    }

    /**
     * Get savings accounts and the balance difference in the period.
     *
     * @return Collection
     */
    public function getSavingsAccounts()
    {
        $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
                        ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
                        ->where('account_meta.name', 'accountRole')
                        ->where('account_meta.data', '"savingAsset"')
                        ->get(['accounts.*']);
        $start    = clone Session::get('start', new Carbon);
        $end      = clone Session::get('end', new Carbon);

        $accounts->each(
            function (Account $account) use ($start, $end) {
                $account->startBalance = Steam::balance($account, $start);
                $account->endBalance   = Steam::balance($account, $end);

                // diff (negative when lost, positive when gained)
                $diff = $account->endBalance - $account->startBalance;

                if ($diff < 0 && $account->startBalance > 0) {
                    // percentage lost compared to start.
                    $pct = (($diff * -1) / $account->startBalance) * 100;
                } else {
                    if ($diff >= 0 && $account->startBalance > 0) {
                        $pct = ($diff / $account->startBalance) * 100;
                    } else {
                        $pct = 100;
                    }
                }
                $pct                 = $pct > 100 ? 100 : $pct;
                $account->difference = $diff;
                $account->percentage = round($pct);

            }
        );

        return $accounts;
    }

    /**
     * Get all transfers TO this account in this range.
     *
     * @param Account $account
     * @param Carbon  $start
     * @param Carbon  $end
     *
     * @return Collection
     */
    public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
    {
        $set      = TransactionJournal::whereIn(
            'id', function (Builder $q) use ($account, $start, $end) {
            $q->select('transaction_journals.id')
              ->from('transactions')
              ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
              ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
              ->where('transactions.account_id', $account->id)
              ->where('transaction_journals.user_id', Auth::user()->id)
              ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
              ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
              ->where('transaction_types.type', 'Transfer');

        }
        )->get();
        $filtered = $set->filter(
            function (TransactionJournal $journal) use ($account) {
                if ($journal->destination_account->id == $account->id) {
                    return $journal;
                }

                return null;
            }
        );

        return $filtered;
    }

    /**
     * @param Account $account
     * @param Carbon  $date
     *
     * @return float
     */
    public function leftOnAccount(Account $account, Carbon $date)
    {

        $balance = Steam::balance($account, $date, true);
        /** @var PiggyBank $p */
        foreach ($account->piggybanks()->get() as $p) {
            $balance -= $p->currentRelevantRep()->currentamount;
        }

        return $balance;

    }

    /**
     * @param Account $account
     *
     * @return TransactionJournal|null
     */
    public function openingBalanceTransaction(Account $account)
    {
        return TransactionJournal
            ::orderBy('transaction_journals.date', 'ASC')
            ->accountIs($account)
            ->orderBy('created_at', 'ASC')
            ->first(['transaction_journals.*']);
    }

    /**
     * @param array $data
     *
     * @return Account
     */
    public function store(array $data)
    {
        $newAccount = $this->storeAccount($data);
        if (!is_null($newAccount)) {
            $this->storeMetadata($newAccount, $data);
        }


        // continue with the opposing account:
        if ($data['openingBalance'] != 0) {
            $type         = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
            $opposingData = [
                'user'           => $data['user'],
                'accountType'    => $type,
                'virtualBalance' => 0,
                'name'           => $data['name'] . ' initial balance',
                'active'         => false,
                'iban'           => '',
            ];
            $opposing     = $this->storeAccount($opposingData);
            if (!is_null($opposing) && !is_null($newAccount)) {
                $this->storeInitialBalance($newAccount, $opposing, $data);
            }

        }

        return $newAccount;

    }

    /**
     * @return float
     */
    public function sumOfEverything()
    {
        return floatval(Auth::user()->transactions()->sum('amount'));
    }

    /**
     * @param Account $account
     * @param array   $data
     *
     * @return Account
     */
    public function update(Account $account, array $data)
    {
        // update the account:
        $account->name            = $data['name'];
        $account->active          = $data['active'] == '1' ? true : false;
        $account->virtual_balance = $data['virtualBalance'];
        $account->iban            = $data['iban'];
        $account->save();

        $this->updateMetadata($account, $data);
        $openingBalance = $this->openingBalanceTransaction($account);

        // if has openingbalance?
        if ($data['openingBalance'] != 0) {
            // if opening balance, do an update:
            if ($openingBalance) {
                // update existing opening balance.
                $this->updateInitialBalance($account, $openingBalance, $data);
            } else {
                // create new opening balance.
                $type         = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
                $opposingData = [
                    'user'           => $data['user'],
                    'accountType'    => $type,
                    'name'           => $data['name'] . ' initial balance',
                    'active'         => false,
                    'virtualBalance' => 0,
                ];
                $opposing     = $this->storeAccount($opposingData);
                if (!is_null($opposing)) {
                    $this->storeInitialBalance($account, $opposing, $data);
                }
            }

        } else {
            if ($openingBalance) { // opening balance is zero, should we delete it?
                $openingBalance->delete(); // delete existing opening balance.
            }
        }

        return $account;
    }

    /**
     * @param array $data
     *
     * @return Account
     */
    protected function storeAccount(array $data)
    {<commit_msg>Forgot one iban key.<commit_after><?php

namespace FireflyIII\Repositories\Account;

use Auth;
use Carbon\Carbon;
use Config;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
use Session;
use Steam;


/**
 * @SuppressWarnings(PHPMD.TooManyMethods)
 *
 * Class AccountRepository
 *
 * @package FireflyIII\Repositories\Account
 */
class AccountRepository implements AccountRepositoryInterface
{

    /**
     * @param array $types
     *
     * @return int
     */
    public function countAccounts(array $types)
    {
        return Auth::user()->accounts()->accountTypeIn($types)->count();
    }

    /**
     * @param Account $account
     *
     * @return boolean
     */
    public function destroy(Account $account)
    {
        $account->delete();

        return true;
    }

    /**
     * @param array $types
     *
     * @return Collection
     */
    public function getAccounts(array $types)
    {
        /** @var Collection $result */
        $result = Auth::user()->accounts()->with(
            ['accountmeta' => function (HasMany $query) {
                $query->where('name', 'accountRole');
            }]
        )->accountTypeIn($types)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);

        $result = $result->sortBy(
            function (Account $account) {
                return strtolower($account->name);
            }
        );

        return $result;
    }


    /**
     * @return Collection
     */
    public function getCreditCards()
    {
        return Auth::user()->accounts()
                   ->hasMetaValue('accountRole', 'ccAsset')
                   ->hasMetaValue('ccType', 'monthlyFull')
                   ->get(
                       [
                           'accounts.*',
                           'ccType.data as ccType',
                           'accountRole.data as accountRole'
                       ]
                   );
    }

    /**
     * @param TransactionJournal $journal
     * @param Account            $account
     *
     * @return Transaction
     */
    public function getFirstTransaction(TransactionJournal $journal, Account $account)
    {

        return $journal->transactions()->where('account_id', $account->id)->first();
    }

    /**
     * @param Preference $preference
     *
     * @return Collection
     */
    public function getFrontpageAccounts(Preference $preference)
    {
        $cache = new CacheProperties();
        $cache->addProperty($preference->data);
        $cache->addProperty('frontPageaccounts');
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }


        if ($preference->data == []) {
            $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
        } else {
            $accounts = Auth::user()->accounts()->whereIn('id', $preference->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
        }

        $cache->store($accounts);

        return $accounts;
    }

    /**
     * This method is used on the front page where (in turn) its viewed journals-tiny.php which (in turn)
     * is almost the only place where formatJournal is used. Aka, we can use some custom querying to get some specific.
     * fields using left joins.
     *
     * @param Account $account
     * @param Carbon  $start
     * @param Carbon  $end
     *
     * @return mixed
     */
    public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
    {
        $cache = new CacheProperties();
        $cache->addProperty($account->id);
        $cache->addProperty($start);
        $cache->addProperty($end);
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }

        $set = Auth::user()
                   ->transactionjournals()
                   ->with(['transactions'])
                   ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
                   ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
                   ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id')
                   ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
                   ->before($end)
                   ->after($start)
                   ->orderBy('transaction_journals.date', 'DESC')
                   ->orderBy('transaction_journals.id', 'DESC')
                   ->take(10)
                   ->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
        $cache->store($set);

        return $set;
    }

    /**
     * @param Account $account
     * @param int     $page
     *
     * @return LengthAwarePaginator
     */
    public function getJournals(Account $account, $page)
    {
        $offset = ($page - 1) * 50;
        $query  = Auth::user()
                      ->transactionJournals()
                      ->withRelevantData()
                      ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
                      ->where('transactions.account_id', $account->id)
                      ->orderBy('transaction_journals.date', 'DESC')
                      ->orderBy('transaction_journals.order', 'ASC')
                      ->orderBy('transaction_journals.id', 'DESC');

        $count     = $query->count();
        $set       = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
        $paginator = new LengthAwarePaginator($set, $count, 50, $page);

        return $paginator;


    }

    /**
     * @param Account $account
     *
     * @return Carbon|null
     */
    public function getLastActivity(Account $account)
    {
        $lastTransaction = $account->transactions()->leftJoin(
            'transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
        )->orderBy('transaction_journals.date', 'DESC')->first(['transactions.*', 'transaction_journals.date']);
        if ($lastTransaction) {
            return $lastTransaction->transactionjournal->date;
        }

        return null;
    }

    /**
     * Get the accounts of a user that have piggy banks connected to them.
     *
     * @return Collection
     */
    public function getPiggyBankAccounts()
    {
        $ids        = [];
        $start      = clone Session::get('start', new Carbon);
        $end        = clone Session::get('end', new Carbon);
        $accountIds = DB::table('piggy_banks')->distinct()->get(['piggy_banks.account_id']);
        $accounts   = new Collection;

        /** @var PiggyBank $id */
        foreach ($accountIds as $id) {
            $ids[] = intval($id->account_id);
        }

        $cache = new CacheProperties;
        $cache->addProperty($ids);
        $cache->addProperty('piggyAccounts');
        if ($cache->has()) {
            return $cache->get(); // @codeCoverageIgnore
        }

        $ids = array_unique($ids);
        if (count($ids) > 0) {
            $accounts = Auth::user()->accounts()->whereIn('id', $ids)->get();
        }

        $accounts->each(
            function (Account $account) use ($start, $end) {
                $account->startBalance = Steam::balance($account, $start, true);
                $account->endBalance   = Steam::balance($account, $end, true);
                $account->piggyBalance = 0;
                /** @var PiggyBank $piggyBank */
                foreach ($account->piggyBanks as $piggyBank) {
                    $account->piggyBalance += $piggyBank->currentRelevantRep()->currentamount;
                }
                // sum of piggy bank amounts on this account:
                // diff between endBalance and piggyBalance.
                // then, percentage.
                $difference          = $account->endBalance - $account->piggyBalance;
                $account->difference = $difference;
                $account->percentage = $difference != 0 && $account->endBalance != 0 ? round((($difference / $account->endBalance) * 100)) : 100;

            }
        );

        $cache->store($accounts);

        return $accounts;

    }

    /**
     * Get savings accounts and the balance difference in the period.
     *
     * @return Collection
     */
    public function getSavingsAccounts()
    {
        $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
                        ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
                        ->where('account_meta.name', 'accountRole')
                        ->where('account_meta.data', '"savingAsset"')
                        ->get(['accounts.*']);
        $start    = clone Session::get('start', new Carbon);
        $end      = clone Session::get('end', new Carbon);

        $accounts->each(
            function (Account $account) use ($start, $end) {
                $account->startBalance = Steam::balance($account, $start);
                $account->endBalance   = Steam::balance($account, $end);

                // diff (negative when lost, positive when gained)
                $diff = $account->endBalance - $account->startBalance;

                if ($diff < 0 && $account->startBalance > 0) {
                    // percentage lost compared to start.
                    $pct = (($diff * -1) / $account->startBalance) * 100;
                } else {
                    if ($diff >= 0 && $account->startBalance > 0) {
                        $pct = ($diff / $account->startBalance) * 100;
                    } else {
                        $pct = 100;
                    }
                }
                $pct                 = $pct > 100 ? 100 : $pct;
                $account->difference = $diff;
                $account->percentage = round($pct);

            }
        );

        return $accounts;
    }

    /**
     * Get all transfers TO this account in this range.
     *
     * @param Account $account
     * @param Carbon  $start
     * @param Carbon  $end
     *
     * @return Collection
     */
    public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
    {
        $set      = TransactionJournal::whereIn(
            'id', function (Builder $q) use ($account, $start, $end) {
            $q->select('transaction_journals.id')
              ->from('transactions')
              ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
              ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
              ->where('transactions.account_id', $account->id)
              ->where('transaction_journals.user_id', Auth::user()->id)
              ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
              ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
              ->where('transaction_types.type', 'Transfer');

        }
        )->get();
        $filtered = $set->filter(
            function (TransactionJournal $journal) use ($account) {
                if ($journal->destination_account->id == $account->id) {
                    return $journal;
                }

                return null;
            }
        );

        return $filtered;
    }

    /**
     * @param Account $account
     * @param Carbon  $date
     *
     * @return float
     */
    public function leftOnAccount(Account $account, Carbon $date)
    {

        $balance = Steam::balance($account, $date, true);
        /** @var PiggyBank $p */
        foreach ($account->piggybanks()->get() as $p) {
            $balance -= $p->currentRelevantRep()->currentamount;
        }

        return $balance;

    }

    /**
     * @param Account $account
     *
     * @return TransactionJournal|null
     */
    public function openingBalanceTransaction(Account $account)
    {
        return TransactionJournal
            ::orderBy('transaction_journals.date', 'ASC')
            ->accountIs($account)
            ->orderBy('created_at', 'ASC')
            ->first(['transaction_journals.*']);
    }

    /**
     * @param array $data
     *
     * @return Account
     */
    public function store(array $data)
    {
        $newAccount = $this->storeAccount($data);
        if (!is_null($newAccount)) {
            $this->storeMetadata($newAccount, $data);
        }


        // continue with the opposing account:
        if ($data['openingBalance'] != 0) {
            $type         = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
            $opposingData = [
                'user'           => $data['user'],
                'accountType'    => $type,
                'virtualBalance' => 0,
                'name'           => $data['name'] . ' initial balance',
                'active'         => false,
                'iban'           => '',
            ];
            $opposing     = $this->storeAccount($opposingData);
            if (!is_null($opposing) && !is_null($newAccount)) {
                $this->storeInitialBalance($newAccount, $opposing, $data);
            }

        }

        return $newAccount;

    }

    /**
     * @return float
     */
    public function sumOfEverything()
    {
        return floatval(Auth::user()->transactions()->sum('amount'));
    }

    /**
     * @param Account $account
     * @param array   $data
     *
     * @return Account
     */
    public function update(Account $account, array $data)
    {
        // update the account:
        $account->name            = $data['name'];
        $account->active          = $data['active'] == '1' ? true : false;
        $account->virtual_balance = $data['virtualBalance'];
        $account->iban            = $data['iban'];
        $account->save();

        $this->updateMetadata($account, $data);
        $openingBalance = $this->openingBalanceTransaction($account);

        // if has openingbalance?
        if ($data['openingBalance'] != 0) {
            // if opening balance, do an update:
            if ($openingBalance) {
                // update existing opening balance.
                $this->updateInitialBalance($account, $openingBalance, $data);
            } else {
                // create new opening balance.
                $type         = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
                $opposingData = [
                    'user'           => $data['user'],
                    'accountType'    => $type,
                    'name'           => $data['name'] . ' initial balance',
                    'active'         => false,
                    'iban'           => '',
                    'virtualBalance' => 0,
                ];
                $opposing     = $this->storeAccount($opposingData);
                if (!is_null($opposing)) {
                    $this->storeInitialBalance($account, $opposing, $data);
                }
            }

        } else {
            if ($openingBalance) { // opening balance is zero, should we delete it?
                $openingBalance->delete(); // delete existing opening balance.
            }
        }

        return $account;
    }

    /**
     * @param array $data
     *
     * @return Account
     */
    protected function storeAccount(array $data)
    {
{'fraction_non_alphanumeric': 0.1447644060907357, 'fraction_numerical': 0.0028765281555826533, 'mean_word_length': 1.8284400424478247, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 360, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3098347', 'n_tokens_mistral': 8859, 'n_tokens_neox': 8391, 'n_words': 1712}