<?php
use Carbon\Carbon;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepository;
use Illuminate\Pagination\LengthAwarePaginator;
use League\FactoryMuffin\Facade as FactoryMuffin;

/**
 * @SuppressWarnings(PHPMD.TooManyMethods)
 * Generated by PHPUnit_SkeletonGenerator on 2015-05-05 at 19:19:32.
 */
class JournalRepositoryTest extends TestCase
{
    /**
     * @var JournalRepository
     */
    protected $object;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    public function setUp()
    {
        $this->object = new JournalRepository;
        parent::setUp();
    }

    /**
     * Tears down the fixture, for example, closes a network connection.
     * This method is called after a test is executed.
     */
    public function tearDown()
    {
        parent::tearDown();
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::deactivateReminder
     */
    public function testDeactivateReminder()
    {
        $reminder         = FactoryMuffin::create('FireflyIII\Models\Reminder');
        $reminder->active = 1;
        $reminder->save();
        $this->be($reminder->user);

        $this->object->deactivateReminder($reminder->id);

        $this->assertEquals(1, Reminder::where('id', $reminder->id)->where('active', 0)->count());
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::delete
     * @covers FireflyIII\Providers\EventServiceProvider::boot
     * @covers FireflyIII\Providers\EventServiceProvider::registerDeleteEvents
     */
    public function testDelete()
    {
        $journal     = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $transaction = $journal->transactions[0];
        $this->object->delete($journal);

        $this->assertEquals(0, TransactionJournal::where('id', $journal->id)->whereNull('deleted_at')->count());
        $this->assertEquals(0, Transaction::where('id', $transaction->id)->whereNull('deleted_at')->count());

    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::first
     */
    public function testFirst()
    {
        $journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $this->be($journal->user);

        $first = $this->object->first();

        $this->assertEquals($journal->id, $first->id);

    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::getAmountBefore
     */
    public function testGetAmountBefore()
    {
        // create some accounts:
        $expense = FactoryMuffin::create('FireflyIII\Models\Account'); // expense
        FactoryMuffin::create('FireflyIII\Models\Account'); // revenue
        $asset = FactoryMuffin::create('FireflyIII\Models\Account'); // asset

        // transaction type
        $withdrawal = FactoryMuffin::create('FireflyIII\Models\TransactionType'); // withdrawal

        // create five journals with incrementing dates:
        $today = new Carbon('2015-01-01');
        for($i=0;$i<5;$i++) {
            // create journal:
            $journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
            $journal->transaction_type_id = $withdrawal;
            $journal->date = $today;
            $journal->save();

            // update transactions:
            $journal->transactions[0]->amount = -100;
            $journal->transactions[0]->account_id = $asset->id;
            $journal->transactions[0]->save();

            $journal->transactions[1]->amount = 100;
            $journal->transactions[1]->account_id = $expense->id;
            $journal->transactions[1]->save();

            // connect to expense
            $today->addDay();
        }


        $before  = $this->object->getAmountBefore($journal, $journal->transactions[1]);
        // five transactions, we check the last one, so amount should be 400.
        $this->assertEquals(400, $before);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::getJournalsOfType
     */
    public function testGetJournalsOfType()
    {
        $user = FactoryMuffin::create('FireflyIII\User');
        $type = FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $this->be($user);
        $result = $this->object->getJournalsOfType($type);
        $this->assertCount(0, $result);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::getJournalsOfTypes
     */
    public function testGetJournalsOfTypes()
    {
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $user = FactoryMuffin::create('FireflyIII\User');
        $this->be($user);
        $types = ['Withdrawal', 'Expense'];
        $set   = $this->object->getJournalsOfTypes($types, 0, 1);

        $this->assertTrue($set instanceof LengthAwarePaginator);
        $this->assertEquals(1, $set->currentPage());
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::getTransactionType
     */
    public function testGetTransactionType()
    {
        $type      = FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $otherType = $this->object->getTransactionType($type->type);
        $this->assertEquals($type->id, $otherType->id);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::getWithDate
     */
    public function testGetWithDate()
    {
        $journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $this->be($journal->user);

        $found = $this->object->getWithDate($journal->id, $journal->date);

        $this->assertEquals($journal->id, $found->id);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::saveTags
     */
    public function testSaveTags()
    {
        $journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $tags    = ['one', 'two', 'three'];
        $this->be($journal->user);

        $this->object->saveTags($journal, $tags);

        $this->assertCount(3, $journal->tags()->get());
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     */
    public function testStore()
    {
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'withdrawal',
            'amount_currency_id' => $currency->id,
            'account_id'         => $account1->id,
            'expense_account'    => 'Some expense account',
            'date'               => '2014-01-01',
            'category'           => 'Some category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     */
    public function testStoreDeposit()
    {
        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');

        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'deposit',
            'amount_currency_id' => $currency->id,
            'account_id'         => $account1->id,
            'revenue_account'    => 'Some revenue account',
            'date'               => '2014-01-01',
            'category'           => 'Some category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     */
    public function testStoreExpenseWithCash()
    {
        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'withdrawal',
            'amount_currency_id' => $currency->id,
            'account_id'         => $account1->id,
            'expense_account'    => '',
            'date'               => '2014-01-01',
            'category'           => 'Some other category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     * @expectedException Symfony\Component\HttpKernel\Exception\HttpException
     */
    public function testStoreInvalidFromAccount()
    {
        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'transfer',
            'amount_currency_id' => $currency->id,
            'account_from_id'    => $account1->id,
            'account_to_id'      => 17,
            'date'               => '2014-01-01',
            'category'           => 'Some other category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     * @expectedException Symfony\Component\HttpKernel\Exception\HttpException
     */
    public function testStoreInvalidToAccount()
    {
        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'transfer',
            'amount_currency_id' => $currency->id,
            'account_from_id'    => 17,
            'account_to_id'      => $account1->id,
            'date'               => '2014-01-01',
            'category'           => 'Some other category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     */
    public function testStoreRevenueWithCash()
    {
        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'deposit',
            'amount_currency_id' => $currency->id,
            'account_id'         => $account1->id,
            'revenue_account'    => '',
            'date'               => '2014-01-01',
            'category'           => 'Some other category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::store
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeWithdrawalAccounts
     * @covers FireflyIII\Repositories\Journal\JournalRepository::storeDepositAccounts
     */
    public function testStoreTransfer()
    {
        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $account2 = FactoryMuffin::create('FireflyIII\Models\Account');
        $user     = FactoryMuffin::create('FireflyIII\User');
        $data     = [
            'description'        => 'Some journal ' . rand(1, 100),
            'user'               => $user->id,
            'what'               => 'transfer',
            'amount_currency_id' => $currency->id,
            'account_from_id'    => $account1->id,
            'account_to_id'      => $account2->id,
            'date'               => '2014-01-01',
            'category'           => 'Some other category',
            'budget_id'          => $budget->id,
            'amount'             => 100,
            'tags'               => ['one', 'two', 'three']


        ];

        $journal = $this->object->store($data);

        $this->assertEquals($data['description'], $journal->description);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::update
     * @covers FireflyIII\Repositories\Journal\JournalRepository::updateTags
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function testUpdate()
    {
        $user = FactoryMuffin::create('FireflyIII\User');
        $this->be($user);

        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $journal  = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $account2 = FactoryMuffin::create('FireflyIII\Models\Account');

        // two transactions
        Transaction::create(
            [
                'account_id'             => $account1->id,
                'transaction_journal_id' => $journal->id,
                'amount'                 => 100,
            ]
        );
        Transaction::create(
            [
                'account_id'             => $account1->id,
                'transaction_journal_id' => $journal->id,
                'amount'                 => -100,
            ]
        );


        $data = [
            'amount_currency_id' => $currency->id,
            'description'        => 'New description ' . rand(1, 100),
            'date'               => '2015-01-01',
            'category'           => 'SomenewCat',
            'amount'             => 50,
            'user'               => $journal->user_id,
            'budget_id'          => $budget->id,
            'account_from_id'    => $account1->id,
            'account_to_id'      => $account2->id,
            'revenue_account'    => 'Some revenue account',
            'expense_account'    => 'Some expense account',
            'tags'               => ['a', 'b', 'c']

        ];

        $result = $this->object->update($journal, $data);

        $this->assertEquals($result->description, $data['description']);
        $this->assertEquals($result->amount, 50);
    }

    /**
     * @covers FireflyIII\Repositories\Journal\JournalRepository::update
     * @covers FireflyIII\Repositories\Journal\JournalRepository::updateTags
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function testUpdateNoTags()
    {
        $user = FactoryMuffin::create('FireflyIII\User');
        $this->be($user);

        for ($i = 0; $i < 4; $i++) {
            FactoryMuffin::create('FireflyIII\Models\AccountType');
        }

        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        FactoryMuffin::create('FireflyIII\Models\TransactionType');
        $journal  = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $currency = FactoryMuffin::create('FireflyIII\Models\TransactionCurrency');
        $budget   = FactoryMuffin::create('FireflyIII\Models\Budget');
        $account1 = FactoryMuffin::create('FireflyIII\Models\Account');
        $account2 = FactoryMuffin::create('FireflyIII\Models\Account');

        // two transactions
        Transaction::create(
            [
                'account_id'             => $account1->id,
                'transaction_journal_id' => $journal->id,
                'amount'                 => 100,
            ]
        );
        Transaction::create(
            [
                'account_id'             => $account1->id,
                'transaction_journal_id' => $journal->id,
                'amount'                 => -100,
            ]
        );


        $data = [
            'amount_currency_id' => $currency->id,
            'description'        => 'New description ' . rand(1, 100),
            'date'               => '2015-01-01',
            'category'           => 'SomenewCat',
            'amount'             => 50,
            'user'               => $journal->user_id,
            'budget_id'          => $budget->id,
            'account_from_id'    => $account1->id,
            'account_to_id'      => $account2->id,
            'revenue_account'    => 'Some revenue account',
            'expense_account'    => 'Some expense account',
            'tags'               => []

        ];

        $result = $this->object->update($journal, $data);

        $this->assertEquals($result->description, $data['description']);
        $this->assertEquals($result->amount, 50);
    }

}
