<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Tests\Product\Repository;

use CpCreation\VitiCore\Product\Model\ProductCollection;
use CpCreation\VitiCore\Product\Model\ProductCollectionItem;
use CpCreation\VitiCore\Product\Repository\ProductCollectionRepository;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
use Doctrine\ORM\ORMSetup;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\Persistence\ManagerRegistry;
use Gedmo\Sortable\SortableListener;
use PHPUnit\Framework\TestCase;
use Ramsey\Uuid\Doctrine\UuidType;
use Ramsey\Uuid\Uuid;

final class ProductCollectionPositionPersistenceTest extends TestCase
{
    public function testDensePositionsSubmittedFromAdminRepairPersistedDuplicates(): void
    {
        if (!Type::hasType('uuid')) {
            Type::addType('uuid', UuidType::class);
        }

        $configuration = ORMSetup::createAttributeMetadataConfiguration([
            \dirname(__DIR__, 3).'/src/Product/Model',
        ], true);
        $configuration->setNamingStrategy(new UnderscoreNamingStrategy());
        $eventManager = new EventManager();
        $eventManager->addEventSubscriber(new SortableListener());
        $connection = DriverManager::getConnection([
            'driver' => 'pdo_sqlite',
            'memory' => true,
        ], $configuration, $eventManager);
        $entityManager = new EntityManager($connection, $configuration);

        $connection->executeStatement('CREATE TABLE product_product (id CHAR(36) NOT NULL PRIMARY KEY)');
        (new SchemaTool($entityManager))->createSchema([
            $entityManager->getClassMetadata(ProductCollection::class),
            $entityManager->getClassMetadata(ProductCollectionItem::class),
        ]);

        $collectionId = Uuid::uuid4()->toString();
        $productIds = array_map(
            static fn (): string => Uuid::uuid4()->toString(),
            range(0, 4),
        );
        $now = '2026-08-26 10:00:00';

        $connection->insert('product_collection', [
            'id' => $collectionId,
            'name' => 'Nos champagnes',
            'mode' => ProductCollection::MODE_MANUAL,
            'automatic_only_cuvee' => 1,
            'automatic_only_new' => 0,
            'automatic_exclude_sold_out' => 0,
            'created_at' => $now,
            'updated_at' => $now,
        ]);

        foreach ($productIds as $index => $productId) {
            $connection->insert('product_product', ['id' => $productId]);
            $connection->insert('product_collection_product', [
                'id' => Uuid::uuid4()->toString(),
                'collection_id' => $collectionId,
                'product_id' => $productId,
                'position' => min($index, 3),
                'created_at' => $now,
                'updated_at' => $now,
            ]);
        }

        $collection = $entityManager->find(ProductCollection::class, $collectionId);
        self::assertInstanceOf(ProductCollection::class, $collection);

        $items = array_values($collection->getItems()->toArray());
        self::assertSame([0, 1, 2, 3, 3], array_map(
            static fn (ProductCollectionItem $item): ?int => $item->getPosition(),
            $items,
        ));

        $movedItemId = $items[4]->getId()->toString();
        $displacedItemId = $items[3]->getId()->toString();

        foreach ($items as $index => $item) {
            $item->setPosition($index);
        }

        $items[4]->setPosition(3);
        $items[3]->setPosition(4);

        $registry = $this->createMock(ManagerRegistry::class);
        $registry->method('getManagerForClass')
            ->with(ProductCollection::class)
            ->willReturn($entityManager);

        (new ProductCollectionRepository($registry))->save($collection);
        $entityManager->clear();

        $persistedItems = $connection->fetchAllAssociative(
            'SELECT id, position FROM product_collection_product WHERE collection_id = ? ORDER BY position ASC',
            [$collectionId],
        );

        self::assertSame([0, 1, 2, 3, 4], array_map(
            static fn (array $item): int => (int) $item['position'],
            $persistedItems,
        ));
        self::assertSame($movedItemId, $persistedItems[3]['id']);
        self::assertSame($displacedItemId, $persistedItems[4]['id']);
    }
}
