<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Marketing;

use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartRule;
use CpCreation\VitiCore\Product\Model\ProductPriceGroup;
use CpCreation\VitiCore\Product\Repository\ProductPriceCodeRepository;
use CpCreation\VitiCore\Product\Repository\ProductPriceGroupRepository;

final readonly class AbandonedCartRuleMatcher
{
    public function __construct(
        private CartRepository $cartRepository,
        private ProductPriceCodeRepository $priceCodeRepository,
        private ProductPriceGroupRepository $priceGroupRepository,
    ) {}

    public function matches(AbandonedCartRule $rule, Cart $cart): bool
    {
        if (!$this->matchesPriceGroup($rule, $cart)) {
            return false;
        }

        $subtotalTTC = $this->calculateSubtotalTTC($cart);

        if (null !== $rule->getMinSubtotalTTC() && $subtotalTTC < $rule->getMinSubtotalTTC()) {
            return false;
        }

        if (null !== $rule->getMaxSubtotalTTC() && $subtotalTTC > $rule->getMaxSubtotalTTC()) {
            return false;
        }

        if ([] !== $rule->getCountryCodes()) {
            $countryCode = $this->resolveCountryCode($cart);

            if (null === $countryCode || !\in_array($countryCode, $rule->getCountryCodes(), true)) {
                return false;
            }
        }

        if (AbandonedCartRule::CUSTOMER_ANY === $rule->getCustomerType()) {
            return true;
        }

        $hasCompletedOrder = $this->cartRepository->hasCompletedOrderForCustomer($cart);

        return match ($rule->getCustomerType()) {
            AbandonedCartRule::CUSTOMER_NEW => !$hasCompletedOrder,
            AbandonedCartRule::CUSTOMER_RETURNING => $hasCompletedOrder,
            default => true,
        };
    }

    public function calculateSubtotalTTC(Cart $cart): int
    {
        $subtotalTTC = 0;

        foreach ($cart->getItems() as $item) {
            $subtotalTTC += max(0, $item->getTotalFinalTTC());
        }

        return $subtotalTTC;
    }

    private function matchesPriceGroup(AbandonedCartRule $rule, Cart $cart): bool
    {
        $rulePriceGroup = $rule->getPriceGroup();
        $cartPriceGroup = $this->resolveCartPriceGroup($cart);

        return $rulePriceGroup instanceof ProductPriceGroup
            && $cartPriceGroup instanceof ProductPriceGroup
            && $rulePriceGroup->getId()->equals($cartPriceGroup->getId());
    }

    private function resolveCartPriceGroup(Cart $cart): ?ProductPriceGroup
    {
        $groupCode = $cart->getGroupCode();
        if (\is_string($groupCode) && '' !== mb_trim($groupCode)) {
            $priceCode = $this->priceCodeRepository->findOneExistingCode($groupCode);
            if ($priceCode?->getGroup() instanceof ProductPriceGroup) {
                return $priceCode->getGroup();
            }
        }

        $userGroup = $cart->getUser()?->getGroup();
        if ($userGroup instanceof ProductPriceGroup) {
            return $userGroup;
        }

        return $this->priceGroupRepository->getGroupByDefault();
    }

    private function resolveCountryCode(Cart $cart): ?string
    {
        $address = $cart->getDeliveryAddress() ?? $cart->getInvoiceAddress();
        $countryCode = $address?->getCountry();

        if (null === $countryCode || '' === mb_trim($countryCode)) {
            return null;
        }

        return mb_strtoupper(mb_trim($countryCode));
    }
}
