<?php

namespace App\Tests\Unit\Service\Dolibarr;

use App\ApiResources\Dolibarr\DolibarrAccount;
use App\ApiResources\Dolibarr\DolibarrBill;
use App\ApiResources\Dolibarr\DolibarrContract;
use App\Service\ApiResourceBuilder\Dolibarr\DolibarrAccountBuilder;
use App\Service\Dolibarr\DolibarrApiService;
use PHPUnit\Framework\TestCase;

class DolibarrAccountCreatorTest extends TestCase
{
    private DolibarrApiService $dolibarrApiService;

    public function setUp(): void {
        $this->dolibarrApiService = $this->getMockBuilder(DolibarrApiService::class)
            ->disableOriginalConstructor()
            ->getMock();
    }

    /**
     * @see DolibarrAccountBuilder::getDolibarrAccount()
     */
    public function testGetDolibarrAccount(): void
    {
        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountBuilder::class)
            ->setConstructorArgs([$this->dolibarrApiService])
            ->setMethodsExcept(['getDolibarrAccount'])
            ->getMock();

        $organizationId = 1;
        $socId = 123;

        // Create dolibarr account
        $accountData = [1]; // dummy non-null data
        $this->dolibarrApiService->expects(self::once())->method('getSociety')->with($organizationId)->willReturn($accountData);

        $dolibarrAccount = $this->getMockBuilder(DolibarrAccount::class)->getMock();
        $dolibarrAccount->method('getSocId')->willReturn($socId);

        $dolibarrAccountCreator
            ->expects(self::once())
            ->method('createDolibarrAccount')
            ->with($organizationId, $accountData)
            ->willReturn($dolibarrAccount);

        // Get active contract and services
        $contractData = [1]; // dummy non-null data
        $this->dolibarrApiService->expects(self::once())->method('getActiveContract')->with($socId)->willReturn($contractData);

        $dolibarrContract = $this->getMockBuilder(DolibarrContract::class)->getMock();

        $dolibarrAccountCreator
            ->expects(self::once())
            ->method('createDolibarrContract')
            ->with($contractData)
            ->willReturn($dolibarrContract);

        $dolibarrAccount->expects(self::once())->method('setContract')->with($dolibarrContract);

        // get bills
        $billsData = [[10], [20]]; // dummy non-empty data

        $dolibarrBill1 = $this->getMockBuilder(DolibarrBill::class)->getMock();
        $dolibarrBill2 = $this->getMockBuilder(DolibarrBill::class)->getMock();

        $this->dolibarrApiService->expects(self::once())->method('getBills')->with($socId)->willReturn($billsData);

        $dolibarrAccountCreator
            ->expects(self::exactly(2))
            ->method('createDolibarrBill')
            ->willReturnMap([
                [[10], $dolibarrBill1],
                [[20], $dolibarrBill2]
            ]);

        $dolibarrAccount->expects(self::exactly(2))->method('addBill')->withConsecutive([$dolibarrBill1], [$dolibarrBill2]);

        $result = $dolibarrAccountCreator->getDolibarrAccount(1);

        $this->assertEquals($dolibarrAccount, $result);
    }

    /**
     * @see DolibarrAccountBuilder::createDolibarrAccount()
     */
    public function testCreateDolibarrAccount(): void
    {
        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountBuilder::class)
            ->setConstructorArgs([$this->dolibarrApiService])
            ->setMethodsExcept(['createDolibarrAccount'])
            ->getMock();

        $organizationId = 1;
        $accountData = ['id' => '2', 'code_client' => 'C2', 'array_options' => []];

        $dolibarrAccount = $dolibarrAccountCreator->createDolibarrAccount($organizationId, $accountData);

        $this->assertEquals(1, $dolibarrAccount->getOrganizationId());
        $this->assertEquals(2, $dolibarrAccount->getSocId());
        $this->assertEquals("C2", $dolibarrAccount->getClientNumber());
        $this->assertEquals(null, $dolibarrAccount->getProduct());
    }

    /**
     * @see DolibarrAccountBuilder::createDolibarrAccount()
     */
    public function testCreateDolibarrAccountWithProduct(): void
    {
        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountBuilder::class)
            ->setConstructorArgs([$this->dolibarrApiService])
            ->setMethodsExcept(['createDolibarrAccount'])
            ->getMock();

        $organizationId = 1;
        $accountData = ['id' => '2', 'code_client' => 'C2', 'array_options' => ['options_2iopen_software_used' => 1]];

        $dolibarrAccount = $dolibarrAccountCreator->createDolibarrAccount($organizationId, $accountData);

        $this->assertEquals('PRODUCT_ARTIST', $dolibarrAccount->getProduct());
    }

    /**
     * @see DolibarrAccountBuilder::createDolibarrContract()
     */
    public function testCreateDolibarrContract(): void
    {
        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountBuilder::class)
            ->setConstructorArgs([$this->dolibarrApiService])
            ->setMethodsExcept(['createDolibarrContract'])
            ->getMock();

        $contractData = [
            'ref' => 'foo',
            'socid' => 123,
            'lines' => [[1], [2]]
        ];

        $dolibarrAccountCreator
            ->expects(self::exactly(2))
            ->method('createDolibarrContractLine')
            ->withConsecutive([[1]], [[2]]);

        $dolibarrContract = $dolibarrAccountCreator->createDolibarrContract($contractData);

        $this->assertEquals('foo', $dolibarrContract->getRef());
        $this->assertEquals(123, $dolibarrContract->getSocId());
    }

    /**
     * @see DolibarrAccountBuilder::createDolibarrContractLine()
     */
    public function testCreateDolibarrContractLine(): void
    {
        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountBuilder::class)
            ->setConstructorArgs([$this->dolibarrApiService])
            ->setMethodsExcept(['createDolibarrContractLine'])
            ->getMock();

        $lineData = [
            'id'=> '1',
            'fk_contrat' => '123',
            'product_ref' => 'foo',
            'product_label' => 'bar',
            'date_start' => '1577836800',
            'date_end' => '1609372800'
        ];

        $dolibarrContractLine = $dolibarrAccountCreator->createDolibarrContractLine($lineData);

        $this->assertEquals(1, $dolibarrContractLine->getId());
        $this->assertEquals(123, $dolibarrContractLine->getContractId());
        $this->assertEquals('foo', $dolibarrContractLine->getServiceRef());
        $this->assertEquals('bar', $dolibarrContractLine->getServiceLabel());
        $this->assertEquals('2020-01-01T00:00:00+00:00', $dolibarrContractLine->getDateStart()->format('c'));
        $this->assertEquals('2020-12-31T00:00:00+00:00', $dolibarrContractLine->getDateEnd()->format('c'));
    }

    /**
     * @see DolibarrAccountBuilder::createDolibarrBill()
     */
    public function testCreateDolibarrBill(): void
    {

        $dolibarrAccountCreator = $this->getMockBuilder(DolibarrAccountBuilder::class)
            ->setConstructorArgs([$this->dolibarrApiService])
            ->setMethodsExcept(['createDolibarrBill'])
            ->getMock();

        $billData = [
            'id' => '1',
            'ref' => 'foo',
            'total_ht' => '100.0',
            'total_ttc' => '120.0',
            'date' => '1577836800',
            'paye' => '0'
        ];

        $dolibarrBill = $dolibarrAccountCreator->createDolibarrBill($billData);

        $this->assertEquals(1, $dolibarrBill->getId());
        $this->assertEquals('foo', $dolibarrBill->getRef());
        $this->assertEquals(100.0, $dolibarrBill->getTaxExcludedAmount());
        $this->assertEquals(120.0, $dolibarrBill->getTaxIncludedAmount());
        $this->assertEquals(false, $dolibarrBill->getPaid());
    }
}
