<?php
use Carbon\Carbon;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepository;
use League\FactoryMuffin\Facade as FactoryMuffin;

/**
 * @SuppressWarnings(PHPMD.TooManyMethods)
 * Generated by PHPUnit_SkeletonGenerator on 2015-05-08 at 10:43:42.
 */
class BillRepositoryTest extends TestCase
{
    /**
     * @var BillRepository
     */
    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 BillRepository;
        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();
    }

    public function testBillPaymentsInRange()
    {
        $user = FactoryMuffin::create('FireflyIII\User');
        $this->be($user);

        $bill  = FactoryMuffin::create('FireflyIII\Models\Bill');
        $start = Carbon::now()->startOfMonth();
        $end   = Carbon::now()->endOfMonth();

        // payment:
        $journal          = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $journal->date    = $start;
        $journal->bill_id = $bill->id;
        $journal->save();


        $this->object->billPaymentsInRange($bill, $start, $end);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::createFakeBill
     */
    public function testCreateFakeBill()
    {
        $description = 'Fake bill ' . rand(10, 100);
        $date        = new Carbon('2013-01-01');
        $amount      = 1200;
        $bill        = $this->object->createFakeBill($description, $date, $amount);

        $this->assertEquals($amount, $bill->amount_max);
        $this->assertEquals($amount, $bill->amount_min);
        $this->assertNull($bill->id);
        $this->assertEquals($description, $bill->name);

    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::destroy
     */
    public function testDestroy()
    {
        $bill      = FactoryMuffin::create('FireflyIII\Models\Bill');
        $accountId = $bill->id;
        $this->object->destroy($bill);

        // cannot find bill:
        $this->assertCount(0, Bill::whereId($accountId)->whereNotNull('deleted_at')->get());
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::getActiveBills
     */
    public function testGetActiveBills()
    {
        $bill1 = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill2 = FactoryMuffin::create('FireflyIII\Models\Bill');

        // update bills
        $bill1->active  = 1;
        $bill2->active  = 0;
        $bill2->user_id = $bill1->user_id;
        $bill1->save();
        $bill2->save();
        $this->be($bill1->user);

        $set = $this->object->getActiveBills();

        $this->assertCount(1, $set);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::getBills
     */
    public function testGetBills()
    {
        $bill1 = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill2 = FactoryMuffin::create('FireflyIII\Models\Bill');

        // update bills
        $bill1->active  = 1;
        $bill2->active  = 0;
        $bill2->user_id = $bill1->user_id;
        $bill1->save();
        $bill2->save();
        $this->be($bill1->user);

        $set = $this->object->getBills();

        $this->assertCount(2, $set);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::getJournals
     */
    public function testGetJournals()
    {
        $bill1 = FactoryMuffin::create('FireflyIII\Models\Bill');

        // update bills
        $bill1->active = 1;
        $bill1->save();
        $this->be($bill1->user);

        $set = $this->object->getJournals($bill1);

        $this->assertCount(0, $set);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::getJournalsInRange
     */
    public function testGetJournalsInRange()
    {
        $bill1 = FactoryMuffin::create('FireflyIII\Models\Bill');

        // update bills
        $bill1->active = 1;
        $bill1->save();
        $this->be($bill1->user);

        $set = $this->object->getJournalsInRange($bill1, new Carbon, new Carbon);

        $this->assertCount(0, $set);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::getPossiblyRelatedJournals
     */
    public function testGetPossiblyRelatedJournals()
    {
        $bill1             = FactoryMuffin::create('FireflyIII\Models\Bill');
        $account           = FactoryMuffin::create('FireflyIII\Models\Account');
        $bill1->amount_min = 100;
        $bill1->amount_max = 1000;
        $account->user_id  = $bill1->user_id;
        $bill1->save();
        $account->save();

        // create some transactions to match our bill:
        for ($i = 0; $i < 8; $i++) {
            $journal          = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
            $journal->user_id = $bill1->user_id;
            $journal->save();
            $journal->transactions[0]->account_id = $account->id;
            $journal->transactions[0]->save();
        }
        $this->be($bill1->user);

        $set = $this->object->getPossiblyRelatedJournals($bill1);
        $this->assertCount(8, $set);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::getRanges
     */
    public function testGetRanges()
    {
        $bill1              = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill1->date        = new Carbon('2012-01-01');
        $bill1->repeat_freq = 'monthly';
        $bill1->save();

        $set = $this->object->getRanges($bill1, new Carbon('2012-01-01'), new Carbon('2012-12-31'));

        $this->assertCount(12, $set);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::lastFoundMatch
     */
    public function testLastFoundMatch()
    {
        $bill             = FactoryMuffin::create('FireflyIII\Models\Bill');
        $journal          = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $journal->bill_id = $bill->id;
        $journal->user_id = $bill->user_id;
        $journal->save();

        $this->be($bill->user);

        $date = $this->object->lastFoundMatch($bill);

        $this->assertEquals($journal->date->format('Y-m-d'), $date->format('Y-m-d'));
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::lastFoundMatch
     */
    public function testLastFoundMatchNull()
    {
        $bill = FactoryMuffin::create('FireflyIII\Models\Bill');

        $this->be($bill->user);

        $date = $this->object->lastFoundMatch($bill);

        $this->assertNull($date);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::nextExpectedMatch
     */
    public function testNextExpectedMatch()
    {
        $bill              = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill->date        = new Carbon('2012-01-07');
        $bill->repeat_freq = 'monthly';
        $bill->save();
        $this->be($bill->user);

        // journal:
        $journal          = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $journal->date    = Carbon::now()->format('Y-m-d');
        $journal->user_id = $bill->user_id;
        $journal->bill_id = $bill->id;
        $journal->save();

        $next  = $this->object->nextExpectedMatch($bill);
        $today = Carbon::now()->endOfMonth()->addDay();
        $this->assertEquals($today->format('Y-m-d'), $next->format('Y-m-d'));


    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::nextExpectedMatch
     */
    public function testNextExpectedMatchInactive()
    {
        $bill         = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill->active = 0;
        $bill->save();
        $this->be($bill->user);

        $this->assertNull($this->object->nextExpectedMatch($bill));


    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::nextExpectedMatch
     */
    public function testNextExpectedMatchNoJournals()
    {
        $bill              = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill->date        = new Carbon('2012-01-07');
        $bill->repeat_freq = 'monthly';
        $bill->save();

        $this->be($bill->user);

        $next  = $this->object->nextExpectedMatch($bill);
        $today = Carbon::now()->startOfMonth();
        $this->assertEquals($today->format('Y-m-d'), $next->format('Y-m-d'));


    }


    /**
     * One
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     *
     * @covers FireflyIII\Repositories\Bill\BillRepository::scan
     * @covers FireflyIII\Repositories\Bill\BillRepository::doWordMatch
     * @covers FireflyIII\Repositories\Bill\BillRepository::doAmountMatch
     */
    public function testScanMatch()
    {
        $user = FactoryMuffin::create('FireflyIII\User');
        $this->be($user);
        $bill              = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill->date        = new Carbon('2012-01-07');
        $bill->repeat_freq = 'monthly';
        $bill->match       = 'jemoeder';
        $bill->amount_min  = 90;
        $bill->amount_max  = 110;
        $bill->save();
        $this->be($bill->user);

        // journal:
        $journal              = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $journal->date        = Carbon::now()->format('Y-m-d');
        $journal->description = 'jemoeder';
        $journal->user_id     = $bill->user_id;
        $journal->save();

        $this->object->scan($bill, $journal);
        $newJournal = TransactionJournal::find($journal->id);

        $this->assertEquals($bill->id, $newJournal->bill_id);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::scan
     * @covers FireflyIII\Repositories\Bill\BillRepository::doWordMatch
     * @covers FireflyIII\Repositories\Bill\BillRepository::doAmountMatch
     */
    public function testScanNoMatch()
    {
        $bill              = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill->date        = new Carbon('2012-01-07');
        $bill->repeat_freq = 'monthly';
        $bill->save();
        $this->be($bill->user);

        // journal:
        $journal          = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $journal->date    = Carbon::now()->format('Y-m-d');
        $journal->user_id = $bill->user_id;
        $journal->save();

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

        $this->object->scan($bill, $journal);
        $newJournal = TransactionJournal::find($journal->id);

        $this->assertNull($newJournal->bill_id);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::scan
     * @covers FireflyIII\Repositories\Bill\BillRepository::doWordMatch
     * @covers FireflyIII\Repositories\Bill\BillRepository::doAmountMatch
     */
    public function testScanNoMatchButAttached()
    {
        $bill              = FactoryMuffin::create('FireflyIII\Models\Bill');
        $bill->date        = new Carbon('2012-01-07');
        $bill->match       = 'blablabla';
        $bill->repeat_freq = 'monthly';
        $bill->save();
        $this->be($bill->user);

        // journal:
        $journal          = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
        $journal->date    = Carbon::now()->format('Y-m-d');
        $journal->user_id = $bill->user_id;
        $journal->bill_id = $bill->id;
        $journal->save();

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

        $this->object->scan($bill, $journal);
        $newJournal = TransactionJournal::find($journal->id);

        $this->assertNull($newJournal->bill_id);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::store
     */
    public function testStore()
    {
        $user = FactoryMuffin::create('FireflyIII\User');
        $data = [
            'name'        => 'Something',
            'match'       => 'Something',
            'amount_min'  => 100,
            'user'        => $user->id,
            'amount_max'  => 110,
            'date'        => new Carbon,
            'repeat_freq' => 'monthly',
            'skip'        => 0,
            'automatch'   => 1,
            'active'      => 1,

        ];
        $bill = $this->object->store($data);

        $this->assertEquals($data['name'], $bill->name);
    }

    /**
     * @covers FireflyIII\Repositories\Bill\BillRepository::update
     */
    public function testUpdate()
    {
        $bill    = FactoryMuffin::create('FireflyIII\Models\Bill');
        $data    = [
            'name'        => 'new Name',
            'match'       => $bill->match,
            'amount_min'  => 100,
            'amount_max'  => 110,
            'date'        => new Carbon,
            'repeat_freq' => 'monthly',
            'skip'        => 0,
            'automatch'   => 1,
            'active'      => 1,

        ];
        $newBill = $this->object->update($bill, $data);

        $this->assertEquals($data['name'], $newBill->name);
        $this->assertEquals($bill->match, $newBill->match);
    }
}
