<?php

declare(strict_types=1);

/*
 * 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\Commerce\Catalog\Outbox;

use CpCreation\VitiCore\Cart\Model\CartCheckout;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Commerce\Catalog\CatalogIdentity;
use CpCreation\VitiCore\Commerce\Catalog\Configuration\CatalogIntegrationConfiguration;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogChangeType;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogResourceType;
use CpCreation\VitiCore\Commerce\Catalog\Outbox\CatalogChangeClassifier;
use CpCreation\VitiCore\Commerce\Catalog\Outbox\CatalogMutationContext;
use CpCreation\VitiCore\Contact\Model\Contact;
use CpCreation\VitiCore\Product\Model\Product;
use CpCreation\VitiCore\Product\Model\ProductCategory;
use CpCreation\VitiCore\Product\Model\ProductVariant;
use PHPUnit\Framework\TestCase;

final class CatalogChangeClassifierTest extends TestCase
{
    private const string INSTANCE_ID = '7ad9e145-910f-4de4-9cec-5f832494adef';

    public function testVariantChangeTargetsItsProduct(): void
    {
        $product = new Product();
        $variant = new ProductVariant();
        $variant->setProduct($product);

        $draft = $this->classifier()->classify($variant);

        self::assertNotNull($draft);
        self::assertSame(CatalogChangeType::PRODUCT_CHANGED, $draft->type);
        self::assertSame(CatalogResourceType::PRODUCT, $draft->resourceType);
        self::assertStringEndsWith('_product_' . str_replace('-', '', $product->getId()->toString()), (string) $draft->resourceId);
    }

    public function testProductDeletionTakesPrecedenceAsRemoval(): void
    {
        $draft = $this->classifier()->classify(
            new Product(),
            CatalogMutationContext::deletion(productRemoval: true),
        );

        self::assertNotNull($draft);
        self::assertSame(CatalogChangeType::PRODUCT_REMOVED, $draft->type);
        self::assertTrue($draft->isProductRemoval());
    }

    public function testSellerAndSharedDataUseTheirDedicatedScopes(): void
    {
        $seller = $this->classifier()->classify(new Contact());
        $shared = $this->classifier()->classify(new ProductCategory());
        $stock = $this->classifier()->classify(
            new CartCheckout(),
            CatalogMutationContext::update(['initiatedAt' => [null, new \DateTimeImmutable()]]),
        );

        self::assertSame(CatalogChangeType::SELLER_CHANGED, $seller?->type);
        self::assertSame(CatalogResourceType::SELLER, $seller?->resourceType);
        self::assertSame(CatalogChangeType::RECONCILIATION_REQUIRED, $shared?->type);
        self::assertSame(CatalogResourceType::CATALOG, $shared?->resourceType);
        self::assertSame(CatalogChangeType::RECONCILIATION_REQUIRED, $stock?->type);
    }

    public function testRoutineCartAndCheckoutUpdatesDoNotCreateStockNotifications(): void
    {
        $classifier = $this->classifier();

        self::assertNull($classifier->classify(
            new Cart(),
            CatalogMutationContext::update(['lastActivityAt' => [null, new \DateTimeImmutable()]]),
        ));
        self::assertNull($classifier->classify(
            new CartCheckout(),
            CatalogMutationContext::update(['response' => [null, ['status' => 'pending']]]),
        ));
        self::assertNull($classifier->classify(
            new CartCheckout(),
            CatalogMutationContext::insertion([]),
        ));
    }

    private function classifier(): CatalogChangeClassifier
    {
        $configuration = new CatalogIntegrationConfiguration(
            enabled: true,
            instanceId: self::INSTANCE_ID,
            apiTokenHash: '',
            currency: 'EUR',
        );

        return new CatalogChangeClassifier(new CatalogIdentity($configuration));
    }
}
