<?php

namespace Unit\Accounting\Export\Exporter\Provider\Product;

use Myvetshop\Module\Clinique\Accounting\Export\Exporter\Provider\Product\ProductProvider;
use Myvetshop\Module\Clinique\Accounting\Export\Repository\CountryRepository;
use Myvetshop\Module\Clinique\Accounting\Export\Repository\InvoiceAddressRepository;
use Myvetshop\Module\Clinique\Accounting\Export\Repository\OrderDetailRepository;
use Myvetshop\Module\Clinique\Accounting\Export\Repository\OrderDetailTaxRepository;
use Myvetshop\Module\Clinique\Accounting\Export\Repository\OrderSlipDetailRepository;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class ProductProviderTest extends TestCase
{
    protected \Order $order;

    /**
     * @var (CountryRepository&MockObject)
     */
    protected CountryRepository $countryRepository;

    /**
     * @var (InvoiceAddressRepository&MockObject)
     */
    protected InvoiceAddressRepository $invoiceAddressRepository;

    /**
     * @var (OrderDetailRepository&MockObject)
     */
    protected OrderDetailRepository $orderDetailRepository;

    /**
     * @var (OrderDetailTaxRepository&MockObject)
     */
    protected OrderDetailTaxRepository $orderDetailTaxRepository;

    /**
     * @var (OrderSlipDetailRepository&MockObject)
     */
    protected OrderSlipDetailRepository $orderSlipDetailRepository;

    protected ProductProvider $productProvider;

    protected function setUp(): void
    {
        $this->order = $this->getMockBuilder(\Order::class)
            ->disableOriginalConstructor()
            ->getMock();

        $country = $this->getMockBuilder(\Country::class)
            ->disableOriginalConstructor()
            ->getMock();
        $country->iso_code = 'FR';

        $invoiceAddress = $this->getMockBuilder(\Address::class)
            ->disableOriginalConstructor()
            ->getMock();
        $invoiceAddress->id_country = 8;

        $this->countryRepository = $this->getMockBuilder(CountryRepository::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->countryRepository
            ->method('getById')
            ->with(8)
            ->willReturn($country);

        $this->invoiceAddressRepository = $this->getMockBuilder(InvoiceAddressRepository::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->invoiceAddressRepository
            ->method('getByOrder')
            ->with($this->order)
            ->willReturn($invoiceAddress);

        $this->orderDetailRepository = $this->getMockBuilder(OrderDetailRepository::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->orderDetailTaxRepository = $this->getMockBuilder(OrderDetailTaxRepository::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->orderSlipDetailRepository = $this->getMockBuilder(OrderSlipDetailRepository::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->productProvider = new ProductProvider(
            $this->countryRepository,
            $this->invoiceAddressRepository,
            $this->orderDetailRepository,
            $this->orderDetailTaxRepository,
            $this->orderSlipDetailRepository
        );
    }

    public function testGetInvoiceAccountingLines(): void
    {
        $orderInvoice = $this->createMock(\OrderInvoice::class);

        $order = $this->getMockBuilder(\Order::class)
            ->disableOriginalConstructor()
            ->getMock();

        $orderDetail1 = $this->createMock(\OrderDetail::class);
        $orderDetail1->id = 100;
        $orderDetail1->total_price_tax_excl = 100;
        $orderDetail2 = $this->createMock(\OrderDetail::class);
        $orderDetail2->id = 101;
        $orderDetail2->total_price_tax_excl = 50;

        $this->orderDetailRepository
            ->method('getByOrder')
            ->with($this->order)
            ->willReturn([$orderDetail1, $orderDetail2]);

        $this->orderDetailTaxRepository
            ->method('getByOrder')
            ->with($this->order)
            ->willReturn([
                100 => ['id_order_detail' => 100, 'rate' => 20.0, 'amount' => 20.0],
                101 => ['id_order_detail' => 101, 'rate' => 5.5, 'amount' => 2.75],
            ]);

        $lines = $this->productProvider->getInvoiceAccountingLines($orderInvoice, $order);

        self::assertCount(2, $lines);
        self::assertEquals('707110000', $lines[0]->getAccount());
        self::assertEquals(100, $lines[0]->getCredit());
        self::assertEquals(0, $lines[0]->getDebit());
        self::assertEquals('707110100', $lines[1]->getAccount());
        self::assertEquals(50, $lines[1]->getCredit());
        self::assertEquals(0, $lines[1]->getDebit());
    }

    public function testGetSlipAccountingLines(): void
    {
        $orderSlip = $this->getMockBuilder(\OrderSlip::class)
            ->disableOriginalConstructor()
            ->getMock();
        $orderSlip->amount = 50;

        $order = $this->getMockBuilder(\Order::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->orderSlipDetailRepository
            ->method('getByOrderSlip')
            ->with($orderSlip)
            ->willReturn(
                [
                    [
                        'id_order_detail' => 100,
                        'product_quantity' => 1,
                        'total_price_tax_excl' => 100,
                        'total_price_tax_incl' => 120,
                        'amount_tax_excl' => 100,
                        'amount_tax_incl' => 120,
                    ],
                    [
                        'id_order_detail' => 101,
                        'product_quantity' => 1,
                        'total_price_tax_excl' => 50,
                        'total_price_tax_incl' => 52.75,
                        'amount_tax_excl' => 50,
                        'amount_tax_incl' => 52.75,
                    ],
                ]);

        $this->orderDetailTaxRepository
            ->method('getByOrder')
            ->with($this->order)
            ->willReturn([
                100 => ['id_order_detail' => 100, 'rate' => 20.0, 'amount' => 20.0],
                101 => ['id_order_detail' => 101, 'rate' => 5.5, 'amount' => 2.75],
            ]);

        $lines = $this->productProvider->getSlipAccountingLines($orderSlip, $order);

        self::assertCount(2, $lines);
        self::assertEquals('707110000', $lines[0]->getAccount());
        self::assertEquals(0, $lines[0]->getCredit());
        self::assertEquals(100, $lines[0]->getDebit());
        self::assertEquals('707110100', $lines[1]->getAccount());
        self::assertEquals(0, $lines[1]->getCredit());
        self::assertEquals(50, $lines[1]->getDebit());
    }
}
