<?php

namespace App\Tests\A_Unit\Import\Sync\Syncer;

use Myvetshop\Module\Clinique\Import\Model\AddressModel;
use Myvetshop\Module\Clinique\Import\Sync\Syncer\AddressesSyncer;
use Myvetshop\Module\Clinique\Import\Sync\SyncStatistics;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class AddressesSyncerTest extends TestCase
{
    /**
     * @var AddressesSyncer&MockObject
     */
    private AddressesSyncer $addressesSyncer;

    protected function createAddressMock(): \Address
    {
        $ret = $this->createMock(\Address::class);

        $ret
            ->expects($this->once())
            ->method('save')
            ->willReturn(true);

        return $ret;
    }

    protected function setUp(): void
    {
        $db = $this->createMock(\Db::class);

        $this->addressesSyncer = $this->getMockBuilder(AddressesSyncer::class)
            ->setConstructorArgs([$db])
            ->onlyMethods(['createAddress', 'getAddresses'])
            ->getMock();
    }

    public function testSync(): void
    {
        $existingAddress = $this->createMock(\Address::class);
        $existingAddress->id = 50;
        $existingAddress->other = '5';

        $this->addressesSyncer
            ->method('getAddresses')
            ->with(1)
            ->willReturn([$existingAddress]);

        $this->addressesSyncer
            ->method('createAddress')
            ->willReturnCallback(fn (): \Address => $this->createAddressMock());

        $syncStats = new SyncStatistics();
        $customer = $this->createMock(\Customer::class);
        $customer->id = 1;
        $addressModelA = new AddressModel();
        $addressModelA->idAddress = 5;
        $addressModelA->idCountry = 1;
        $addressModelA->alias = 'home';
        $addressModelA->lastname = 'Doe';
        $addressModelA->firstname = 'John';
        $addressModelA->address1 = '100 Main St';
        $addressModelA->postcode = '12345';
        $addressModelA->city = 'City';
        $addressModelA->dateAdd = new \DateTimeImmutable();
        $addressModelA->dateUpd = new \DateTimeImmutable();

        $addressModelB = new AddressModel();
        $addressModelB->idAddress = 6;
        $addressModelB->idCountry = 1;
        $addressModelB->alias = 'work';
        $addressModelB->lastname = 'Doe';
        $addressModelB->firstname = 'Jane';
        $addressModelB->address1 = '101 Main St';
        $addressModelB->postcode = '54321';
        $addressModelB->city = 'BigCity';
        $addressModelB->dateAdd = new \DateTimeImmutable();
        $addressModelB->dateUpd = new \DateTimeImmutable();

        $result = $this->addressesSyncer->sync($syncStats, $customer, [$addressModelA, $addressModelB]);

        $this->assertIsArray($result, 'Return value must be an array');
        $this->assertCount(2, $result);
        $this->assertArrayHasKey($addressModelA->idAddress, $result);
        $this->assertSame($existingAddress, $result[$addressModelA->idAddress]);
        $this->assertEquals(1, $syncStats->nbAddressesUpdated);
        $this->assertEquals(1, $syncStats->nbAddressesCreated);
        $this->assertEquals($addressModelB->alias, $result[$addressModelB->idAddress]->alias);
        $this->assertEquals($addressModelB->address1, $result[$addressModelB->idAddress]->address1);
        $this->assertEquals($addressModelB->lastname, $result[$addressModelB->idAddress]->lastname);
        $this->assertEquals($addressModelB->firstname, $result[$addressModelB->idAddress]->firstname);
        $this->assertEquals($addressModelB->postcode, $result[$addressModelB->idAddress]->postcode);
        $this->assertEquals($addressModelB->city, $result[$addressModelB->idAddress]->city);
        $this->assertEquals((string) $addressModelB->idAddress, $result[$addressModelB->idAddress]->other);
    }
}
