<?php

namespace Tests\Units\Repository;

use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

use Carbon\Carbon;
use App\Services\Stock\MovementService;

use App\Repositories\Stock\MovementRepository;

use App\Models\Stock\Good;
use App\Models\Stock\Purchase;
use App\Models\Stock\Movement;
use App\Models\Stock\InventoryViewModel;

class MovementRepositoryTest extends \TestCase
{
    use DatabaseTransactions;

    /**
     * Test case one
     * We have no movements in range
     */
    public function testCaseOne()
    {
        $good = factory(\App\Models\Stock\Good::class)->make();
        $good->average_unit_price = 0;
        $good->save();

        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->subDays(15);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->addDays(15);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        // act
        $repo = new MovementRepository;
        $model = $repo->inventory(Carbon::now('UTC')->subDays(10), Carbon::now('UTC'));

        // assert
        $this->assertTrue($model instanceof InventoryViewModel);
    }

    /**
     * Test case two
     * We have a movement in range
     */
    public function testCaseTwo()
    {
        // arrange
        $good = factory(\App\Models\Stock\Good::class)->make();
        $good->average_unit_price = 0;
        $good->save();

        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->subDays(5);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        // act
        $repo = new MovementRepository;
        $model = $repo->inventory(Carbon::now('UTC')->subDays(10), Carbon::now('UTC'));

        // assert
        $this->assertTrue($model instanceof InventoryViewModel);
        //$this->assertEquals(0, $model->quantityStart());
        //$this->assertEquals(1, $model->quantityIn());
        //$this->assertEquals(0, $model->quantityOut());
        //$this->assertEquals(1, $model->quantityEnd());

        $this->assertEquals(0, $model->beginningValue());
        $this->assertEquals(200, $model->inValue());
        $this->assertEquals(0, $model->outValue());
        $this->assertEquals(200, $model->endingValue());
    }

    /**
     * Test case three
     * We have a movement before range and one in range
     */
    public function testCaseThree()
    {
        // arrange
        $good = factory(\App\Models\Stock\Good::class)->make();
        $good->average_unit_price = 0;
        $good->save();

        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->subDays(15);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->subDays(5);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        // act
        $repo = new MovementRepository;
        $model = $repo->inventory(Carbon::now('UTC')->subDays(10), Carbon::now('UTC'));

        // assert
        $this->assertTrue($model instanceof InventoryViewModel);
        //$this->assertEquals(1, $model->quantityStart());
        //$this->assertEquals(1, $model->quantityIn());
        //$this->assertEquals(0, $model->quantityOut());
        //$this->assertEquals(2, $model->quantityEnd());

        $this->assertEquals(200, $model->beginningValue());
        $this->assertEquals(200, $model->inValue());
        $this->assertEquals(0, $model->outValue());
        $this->assertEquals(400, $model->endingValue());
    }

    /**
     * Test case four
     * We have a movement before, in and after range
     */
    public function testCaseFour()
    {
        // arrange
        //$supplier = factory(\App\Models\Stock\Account::class)->create();
        //$stockAccount = factory(\App\Models\Stock\Account::class, 'defaultAccount')->create();

        $good = factory(\App\Models\Stock\Good::class)->make();
        $good->average_unit_price = 0;
        $good->save();

        //$php = \App\Models\Base\Currency::where('name', '=', 'Peso')->first();

        //$service = new MovementService;
        //$service->moveGood($supplier->id, $stockAccount->id, $good->id, $php->id, 1, 200, Carbon::now('UTC')->subDays(15), "");

        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->subDays(15);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        //$service->moveGood($supplier->id, $stockAccount->id, $good->id, $php->id, 1, 200, Carbon::now('UTC')->subDays(5), "");
        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->subDays(5);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        //$service->moveGood($supplier->id, $stockAccount->id, $good->id, $php->id, 1, 200, Carbon::now('UTC')->addDays(5), "");
        $purchase = factory(Purchase::class)->make();
        //$purchase->supplier_id = $supplier->id;
        //$purchase->stock_room_id = $stockRoom->id;
        $purchase->stock_good_id = $good->id;
        $purchase->quantity = 1;
        $purchase->unit_price = 200;
        //$purchase->currency_id = $php->id;
        $purchase->purchased_at = Carbon::now('UTC')->addDays(5);
        $purchase->save();

        Good::updateAverageUnitPrice($good->id);

        // act
        $repo = new MovementRepository;
        $model = $repo->inventory(Carbon::now('UTC')->subDays(10), Carbon::now('UTC'));

        // assert
        $this->assertTrue($model instanceof InventoryViewModel);
        //$this->assertEquals(1, $model->quantityStart());
        //$this->assertEquals(1, $model->quantityIn());
        //$this->assertEquals(0, $model->quantityOut());
        //$this->assertEquals(2, $model->quantityEnd());

        $this->assertEquals(200, $model->beginningValue());
        $this->assertEquals(200, $model->inValue());
        $this->assertEquals(0, $model->outValue());
        $this->assertEquals(400, $model->endingValue());
    }

    /**
     * Test case five
     * We have a purchase before, in and after the range
     * We have a movement before, in and after the range
     */
    public function testCaseFive()
    {
        // arrange
        //$supplier = factory(\App\Models\Stock\Account::class)->create();
        $stockRoom = factory(\App\Models\Stock\StockRoom::class)->create();
        //$internalAccount = factory(\App\Models\Stock\Account::class, 'internalAccount')->create();

        //dd($internalAccount);

        $good = factory(\App\Models\Stock\Good::class)->make();
        $good->average_unit_price = 0;
        $good->save();

        //$php = \App\Models\Base\Currency::where('name', '=', 'Peso')->first();

        //$service = new MovementService;
        //$service->handlePurchase($supplier->id, $stockAccount->id, $good->id, $php->id, 5, 200, Carbon::now('UTC')->subDays(15), "unit test");

        $p1 = factory(Purchase::class)->make();
        //$p1->supplier_id = $supplier->id;
        $p1->stock_room_id = $stockRoom->id;
        $p1->stock_good_id = $good->id;
        $p1->quantity = 5;
        $p1->unit_price = 200;
        //$p1->currency_id = $php->id;
        $p1->purchased_at = Carbon::now('UTC')->subDays(15);
        $p1->save();

        Good::updateAverageUnitPrice($good->id);
        $good = Good::findOrFail($good->id);

        //$service->handleMovement($stockAccount->id, $internalAccount->id, $good->id, $php->id, 3, Carbon::now('UTC')->subDays(15), "unit test");

        $m1 = factory(Movement::class)->make();
        //$m1->supplier_id = $supplier->id;
        $m1->stock_room_id = $stockRoom->id;
        $m1->stock_good_id = $good->id;
        $m1->quantity = 3;
        $m1->unit_price = $good->average_unit_price;
        //$m1->currency_id = $php->id;
        $m1->moved_at = Carbon::now('UTC')->subDays(15);
        $m1->save();

        //$service->handlePurchase($supplier->id, $stockAccount->id, $good->id, $php->id, 10, 140, Carbon::now('UTC')->subDays(5), "unit test");

        $p2 = factory(Purchase::class)->make();
        //$p2->supplier_id = $supplier->id;
        $p2->stock_room_id = $stockRoom->id;
        $p2->stock_good_id = $good->id;
        $p2->quantity = 10;
        $p2->unit_price = 140;
        //$p2->currency_id = $php->id;
        $p2->purchased_at = Carbon::now('UTC')->subDays(5);
        $p2->save();

        Good::updateAverageUnitPrice($good->id);
        $good = Good::findOrFail($good->id);

        //$service->handleMovement($stockAccount->id, $internalAccount->id, $good->id, $php->id, 7, Carbon::now('UTC')->subDays(5), "unit test");

        $m2 = factory(Movement::class)->make();
        //$m2->supplier_id = $supplier->id;
        $m2->stock_room_id = $stockRoom->id;
        $m2->stock_good_id = $good->id;
        $m2->quantity = 7;
        $m2->unit_price = $good->average_unit_price;
        //$m2->currency_id = $php->id;
        $m2->moved_at = Carbon::now('UTC')->subDays(5);
        $m2->save();

        // $service->handlePurchase($supplier->id, $stockAccount->id, $good->id, $php->id, 100, 200, Carbon::now('UTC')->addDays(5), "unit test");

        $p3 = factory(Purchase::class)->make();
        //$p3->supplier_id = $supplier->id;
        $p3->stock_room_id = $stockRoom->id;
        $p3->stock_good_id = $good->id;
        $p3->quantity = 100;
        $p3->unit_price = 200;
        //$p3->currency_id = $php->id;
        $p3->purchased_at = Carbon::now('UTC')->addDays(5);
        $p3->save();

        Good::updateAverageUnitPrice($good->id);
        $good = Good::findOrFail($good->id);

        //$service->handleMovement($stockAccount->id, $internalAccount->id, $good->id, $php->id, 30, Carbon::now('UTC')->addDays(5), "unit test");

        $m3 = factory(Movement::class)->make();
        //$m3->supplier_id = $supplier->id;
        $m3->stock_room_id = $stockRoom->id;
        $m3->stock_good_id = $good->id;
        $m3->quantity = 30;
        $m3->unit_price = $good->average_unit_price;
        //$m3->currency_id = $php->id;
        $m3->moved_at = Carbon::now('UTC')->addDays(5);
        $m3->save();

        // act
        $repo = new MovementRepository;
        $model = $repo->inventory(Carbon::now('UTC')->subDays(10), Carbon::now('UTC'));

        // assert
        $this->assertTrue($model instanceof InventoryViewModel);
        //$this->assertEquals(2, $model->quantityStart());
        //$this->assertEquals(10, $model->quantityIn());
        //$this->assertEquals(7, $model->quantityOut());
        //$this->assertEquals(5, $model->quantityEnd());

        $this->assertEquals(320, $model->beginningValue());
        $this->assertEquals(1600, $model->inValue());
        $this->assertEquals(1120, $model->outValue());
        $this->assertEquals(800, $model->endingValue());
    }
}
