<?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\Cart;

use CpCreation\VitiCore\Cart\CartPricing;
use CpCreation\VitiCore\Cart\CartPricingLine;
use CpCreation\VitiCore\Cart\CartShipping;
use CpCreation\VitiCore\Cart\CustomerOrderInsightsBuilder;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\CartCheckout;
use CpCreation\VitiCore\Shop\Model\DeliveryMethod;
use PHPUnit\Framework\TestCase;

final class CustomerOrderInsightsBuilderTest extends TestCase
{
    public function testItBuildsHistoricalCustomerIndicatorsFromFrozenOrderSnapshots(): void
    {
        $homeDelivery = new DeliveryMethod();
        $homeDelivery->setDepot(false);
        $pickup = new DeliveryMethod();
        $pickup->setDepot(true);

        $olderOrder = $this->order(
            orderedAt: new \DateTimeImmutable('2025-04-12 09:00:00'),
            totalTTC: 6000,
            lines: [
                $this->line('Cuvée Brut', 'Bouteille', '75 cl', 6, 4200, 'product-brut', 'type-bottle'),
                $this->line('Cuvée Brut', 'Magnum', '1,5 L', 1, 1800, 'product-brut', 'type-magnum'),
            ],
            deliveryMethod: $homeDelivery,
            shippingName: 'Livraison historique à domicile',
        );
        $newerOrder = $this->order(
            orderedAt: new \DateTimeImmutable('2026-08-20 14:30:00'),
            totalTTC: 3000,
            lines: [
                $this->line('Cuvée Brut renommée', 'Bouteille', '75 cl', 3, 3000, 'product-brut', 'type-bottle'),
                $this->line('Cadeau', 'Bouteille', '75 cl', 1, 0, 'gift', 'type-bottle', true),
            ],
            deliveryMethod: $pickup,
            shippingName: 'Retrait à la propriété historique',
        );

        $insights = (new CustomerOrderInsightsBuilder())->build([$olderOrder, $newerOrder]);

        self::assertSame(2, $insights['summary']['order_count']);
        self::assertSame(2, $insights['summary']['priced_order_count']);
        self::assertSame(9000, $insights['summary']['total_spent_ttc']);
        self::assertSame(4500, $insights['summary']['average_basket_ttc']);
        self::assertSame(10, $insights['summary']['total_quantity']);
        self::assertSame('2025-04-12', $insights['summary']['first_order_at']?->format('Y-m-d'));
        self::assertSame('2026-08-20', $insights['summary']['last_order_at']?->format('Y-m-d'));
        self::assertSame($newerOrder, $insights['orders'][0]);

        self::assertCount(2, $insights['cuvees']);
        self::assertSame('Cuvée Brut renommée', $insights['cuvees'][0]['name']);
        self::assertSame('Bouteille', $insights['cuvees'][0]['type_name']);
        self::assertSame('75 cl', $insights['cuvees'][0]['unit_label']);
        self::assertSame(9, $insights['cuvees'][0]['quantity']);
        self::assertSame(2, $insights['cuvees'][0]['order_count']);
        self::assertSame(7200, $insights['cuvees'][0]['total_ttc']);
        self::assertSame('Magnum', $insights['cuvees'][1]['type_name']);

        self::assertCount(2, $insights['delivery_methods']);
        self::assertSame('Livraison historique à domicile', $insights['delivery_methods'][0]['name']);
        self::assertSame('address', $insights['delivery_methods'][0]['kind']);
        self::assertSame('Retrait à la propriété historique', $insights['delivery_methods'][1]['name']);
        self::assertSame('pickup', $insights['delivery_methods'][1]['kind']);
    }

    public function testItKeepsAnUnpricedConfirmedOrderWithoutInventingAnAverage(): void
    {
        $order = new Cart();
        $order->generateTimestampsAtCreation();
        $checkout = new CartCheckout();
        $checkout->setOrderedAt(new \DateTimeImmutable('2026-08-20 14:30:00'));
        $order->setCartCheckout($checkout);

        $insights = (new CustomerOrderInsightsBuilder())->build([$order]);

        self::assertSame(1, $insights['summary']['order_count']);
        self::assertSame(0, $insights['summary']['priced_order_count']);
        self::assertNull($insights['summary']['average_basket_ttc']);
        self::assertSame(0, $insights['summary']['total_quantity']);
        self::assertSame([], $insights['cuvees']);
        self::assertSame('other', $insights['delivery_methods'][0]['kind']);
    }

    /**
     * @param list<CartPricingLine> $lines
     */
    private function order(
        \DateTimeImmutable $orderedAt,
        int $totalTTC,
        array $lines,
        DeliveryMethod $deliveryMethod,
        string $shippingName,
    ): Cart {
        $order = new Cart();
        $order->generateTimestampsAtCreation();
        $order->setDeliveryMethod($deliveryMethod);
        $order->setCartShipping(new CartShipping(1000, 0.2, $shippingName));
        $order->setPricing(new CartPricing(
            lines: $lines,
            taxRate: 0.2,
            subtotalHT: $totalTTC,
            subtotalTax: 0,
            subtotalTTC: $totalTTC,
            discountHT: 0,
            discountTax: 0,
            discountTTC: 0,
            degressiveHT: 0,
            degressiveTax: 0,
            degressiveTTC: 0,
            totalHT: $totalTTC,
            totalTax: 0,
            totalTTC: $totalTTC,
        ));
        $checkout = new CartCheckout();
        $checkout->setOrderedAt($orderedAt);
        $order->setCartCheckout($checkout);

        return $order;
    }

    private function line(
        string $productName,
        string $typeName,
        string $unitLabel,
        int $quantity,
        int $netTTC,
        string $productId,
        string $typeId,
        bool $isPromoGift = false,
    ): CartPricingLine {
        return new CartPricingLine(
            itemId: null,
            productId: $productId,
            productName: $productName,
            variantId: null,
            variantFullName: $productName.' - '.$typeName,
            typeId: $typeId,
            typeName: $typeName,
            unitLabel: $unitLabel,
            imagePath: null,
            quantity: $quantity,
            unitPriceHT: 0,
            unitPriceTTC: 0,
            unitPriceDiscountHT: null,
            unitPriceDiscountTTC: null,
            totalHT: 0,
            totalTTC: $netTTC,
            totalDiscountTTC: 0,
            totalDiscountHT: 0,
            unitDegressiveTTC: null,
            unitDegressiveHT: null,
            degressiveTTC: 0,
            degressiveHT: 0,
            netTTC: $netTTC,
            netHT: 0,
            tax: 0,
            isPromoGift: $isPromoGift,
        );
    }
}
