<?php

namespace domain\Order\Order;

use common\helpers\GlobalParam;
use common\helpers\MeanPayment;
use domain\Distribution\Distribution\Distribution;
use domain\Distribution\Distribution\DistributionRepository;
use domain\Distribution\ProductDistribution\ProductDistributionRepository;
use domain\Document\DeliveryNote\DeliveryNote;
use domain\Document\Invoice\Invoice;
use domain\Document\Invoice\InvoiceRepository;
use domain\Document\Invoice\InvoiceSolver;
use domain\Order\OrderStatus\OrderStatus;
use domain\Order\ProductOrder\ProductOrderRepository;
use domain\Payment\Payment;
use domain\Payment\PaymentSolver;
use domain\PointSale\PointSale\PointSale;
use domain\PointSale\PointSale\PointSaleRepository;
use domain\PointSale\PointSale\PointSaleSolver;
use domain\PointSale\UserPointSale\UserPointSaleRepository;
use domain\Producer\Producer\Producer;
use domain\Producer\Producer\ProducerRepository;
use domain\Producer\Producer\ProducerSolver;
use domain\Product\Product\ProductSolver;
use domain\Subscription\Subscription\Subscription;
use domain\User\User\User;
use domain\User\UserProducer\UserProducerRepository;
use domain\_\AbstractRepository;
use phpDocumentor\Reflection\Types\Parent_;
use yii\helpers\Html;

class OrderRepository extends AbstractRepository
{
    protected OrderRepositoryQuery $query;
    protected ProductOrderRepository $productOrderRepository;
    protected ProducerRepository $producerRepository;
    protected OrderSolver $orderSolver;
    protected ProductDistributionRepository $productDistributionRepository;
    protected ProductSolver $productSolver;
    protected UserProducerRepository $userProducerRepository;
    protected DistributionRepository $distributionRepository;
    protected PointSaleRepository $pointSaleRepository;
    protected UserPointSaleRepository $userPointSaleRepository;
    protected InvoiceRepository $invoiceRepository;
    protected InvoiceSolver $invoiceSolver;
    protected PaymentSolver $paymentSolver;
    protected ProducerSolver $producerSolver;
    protected PointSaleSolver $pointSaleSolver;

    public function loadDependencies(): void
    {
        $this->loadQuery(OrderRepositoryQuery::class);
        $this->productOrderRepository = $this->loadService(ProductOrderRepository::class);
        $this->producerRepository = $this->loadService(ProducerRepository::class);
        $this->orderSolver = $this->loadService(OrderSolver::class);
        $this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class);
        $this->productSolver = $this->loadService(ProductSolver::class);
        $this->userProducerRepository = $this->loadService(UserProducerRepository::class);
        $this->distributionRepository = $this->loadService(DistributionRepository::class);
        $this->pointSaleRepository = $this->loadService(PointSaleRepository::class);
        $this->userPointSaleRepository = $this->loadService(UserPointSaleRepository::class);
        $this->invoiceRepository = $this->loadService(InvoiceRepository::class);
        $this->invoiceSolver = $this->loadService(InvoiceSolver::class);
        $this->paymentSolver = $this->loadService(PaymentSolver::class);
        $this->producerSolver = $this->loadService(ProducerSolver::class);
        $this->pointSaleSolver = $this->loadService(PointSaleSolver::class);
    }

    public function getDefaultOptionsSearch(): array
    {
        return [
            self::WITH => [
                'productOrder',
                'productOrder.product',
                'productOrder.taxRate',
                'payment',
                'payment.user',
                'payment.userAction',
                'deliveryNote',
                'invoice',
                'quotation'
            ],
            self::JOIN_WITH => [
                'distribution',
                'user',
                'user.userProducer',
                'pointSale',
            ],
            self::ORDER_BY => 'order.date ASC',
            self::ATTRIBUTE_ID_PRODUCER => 'distribution.id_producer'
        ];
    }

    public function defaultStatus(): void
    {
        parent::defaultStatus();
        $this->query->filterIsOrderStatusNotDeleted();
    }

    public function findOrdersWithOrderStatusAliasNull()
    {
        $this->createQuery();
        $this->defaultFilterProducerContext();

        return $this->query
            ->filterIsOrderStatusAliasNull()
            //->limit(100)
            ->find();
    }

    public function findOneOrderById(int $id)
    {
        return $this->createDefaultQuery()
            ->filterById($id)
            ->findOne();
    }

    public function countGlobalOrdersByDateAndOrigin(\DateTime $date, string $origin = Order::ORIGIN_USER)
    {
        return $this->createQuery()
            ->filterIsOrderStatusNotDeleted()
            ->filterByDate($date)
            ->filterByOrigin($origin)
            ->count();
    }

    public function countGlobalUserOrdersAverageLastSevenDays()
    {
        $count = 0;
        $date = new \DateTime();

        for($i = 0; $i < 7; $i++) {
            $date->modify('-1 day');
            $count += $this->countGlobalOrdersByDateAndOrigin($date);
        }

        return intval($count / 7);
    }

    public function findOrdersByDistributionDate(string $date): array
    {
        return $this->createDefaultQuery()
            ->filterByDistributionDate($date)
            ->find();
    }

    public function findOrdersByDistribution(Distribution $distribution, bool $filterIsValid = true, string $conditionAppend = '')
    {
        $query = $this->createDefaultQuery()
            ->filterByDistributionDate($distribution->date)
            ->filterByCondition($conditionAppend)
            ->orderBy('point_sale.name ASC, user.lastname ASC, user.name ASC, comment_point_sale ASC');

        if($filterIsValid) {
            $query->filterIsValid();
        }

        return $query->find();
    }

    public function findOrdersByPeriod(\DateTime $dateStart, \DateTime $dateEnd)
    {
        $query = $this->createDefaultQuery()
            ->filterByDistributionDateStartEnd($dateStart, $dateEnd)
            ->filterIsValid()
            ->orderBy('distribution.date ASC');

        return $query->find();
    }

    public function findOrdersByUserAndInvoice(User $user, Invoice $invoice)
    {
        return $this
            ->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsInvoiced($invoice)
            ->filterIsValid()
            ->find();
    }

    public function findOrdersByUserAndDeliveryNote(User $user, DeliveryNote $deliveryNote)
    {
        return $this
            ->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsLinkedDeliveryNote($deliveryNote)
            ->filterIsValid()
            ->find();
    }

    public function findOrdersByUserNotInvoiced(User $user)
    {
        return $this
            ->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsNotInvoiced()
            ->filterIsPassed()
            ->filterIsValid()
            ->filterIsNotIgnoreWhenInvoicing()
            ->orderByDistributionDate('DESC')
            ->limit(20)
            ->find();
    }

    public function findOrdersByUserNotLinkedDeliveryNote(User $user)
    {
        return $this
            ->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsNotLinkedDeliveryNote()
            ->filterIsPassed()
            ->filterIsValid()
            ->filterIsNotIgnoreWhenInvoicing()
            ->orderByDistributionDate('DESC')
            ->limit(20)
            ->find();
    }

    public function findOrdersByUser(User $user)
    {
        return $this
            ->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsValid()
            ->find();
    }

    public function queryOrdersHistory(Producer $producer, User $user)
    {
        $queryIncoming = clone $this->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsIncoming()
            ->orderByDistributionDate('ASC');

        $queryPassed = clone $this->createDefaultQuery()
            ->filterByUser($user)
            ->filterIsPassed()
            ->orderByDistributionDate('DESC');

        return [
            'incoming' => $queryIncoming,
            'passed' => $queryPassed
        ];
    }

    /**
     * Retourne le résumé du panier au format HTML.
     * @TODO : à déplacer dans OrderSolver
     */
    public function getCartSummary(Order $order, bool $htmlFormat = true): string
    {
        if (!isset($order->productOrder)) {
            $order->productOrder = $this->productOrderRepository->findProductOrdersByOrder($order);
        }

        $html = '';
        $i = 0;
        $count = count($order->productOrder);

        foreach ($order->productOrder as $productOrder) {
            if (isset($productOrder->product)) {
                $html .=
                    '<strong>' . $productOrder->quantity . ($htmlFormat ? '&nbsp;' : ' '). $this->productSolver->strUnit($productOrder->product, 'wording_short', true) . '</strong> '.
                    Html::encode($productOrder->product->name);

                if (++$i != $count) {
                    if ($htmlFormat) {
                        $html .= '<br />';
                    }
                    else {
                        $html .= "\n";
                    }
                }
            }
        }

        return $html;
    }

    /**
     * Retourne le résumé du paiement (montant, statut).
     * @TODO : à déplacer dans OrderSolver
     */
    public function getAmountSummary(Order $order, string $context = 'admin'): string
    {
        $html = '';
        $html .= $this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL, true);
        $html .= '<br />'.$this->getPaymentLabelShort($order, $context);
        return $html;
    }

    /**
     * Retourne l'état de la commande (livrée, modifiable ou en préparation.
     * @TODO : à déplacer dans OrderSolver
     */
    public function getState(Order $order): string
    {
        $orderDate = strtotime($order->distribution->date);
        $today = strtotime(date('Y-m-d'));
        $todayHour = date('G');
        $dayDistribution = strtolower(date('l', strtotime($order->distribution->date)));

        $orderDelay = $this->producerSolver->getConfig('order_delay');
        $orderDelaySpecific = $this->producerSolver->getConfig('order_delay_' . $dayDistribution,);
        if ($orderDelaySpecific) {
            $orderDelay = $orderDelaySpecific;
        }

        $orderDeadline = $this->producerSolver->getConfig('order_deadline',);
        $orderDeadlineSpecific = $this->producerSolver->getConfig('order_deadline_' . $dayDistribution,);
        if ($orderDeadlineSpecific) {
            $orderDeadline = $orderDeadlineSpecific;
        }

        $nbDays = (int) round((($orderDate - $today) / (24 * 60 * 60)));

        if ($nbDays <= 0) {
            return Order::STATE_DELIVERED;
        } elseif ($nbDays >= $orderDelay &&
            ($nbDays != $orderDelay ||
                ($nbDays == $orderDelay && $todayHour < $orderDeadline))) {
            return Order::STATE_OPEN;
        }

        return Order::STATE_PREPARATION;
    }

    public function isOrderStateOpen(Order $order): bool
    {
        return Order::STATE_OPEN == $this->getState($order);
    }

    public function isOrderStatePreparation(Order $order): bool
    {
        return Order::STATE_PREPARATION == $this->getState($order);
    }

    public function isOrderStateDelivered(Order $order): bool
    {
        return Order::STATE_DELIVERED == $this->getState($order);
    }

    public function findOneOrderLastOfYear(Producer $producer)
    {
        return $this->createDefaultQuery()
            ->innerJoinWith('distribution', true)
            ->where(['>=', 'distribution.date', date('Y') . '-01-01'])
            ->andWhere(['not', ['order.reference' => null]])
            ->orderBy('order.reference DESC')
            ->findOne();
    }

    public function findProductDistributionsByDistribution(Distribution $distribution): array
    {
        $orderArray = $this->findOrdersByDistribution($distribution);
        $productDistributionArray = $this->productDistributionRepository->findProductDistributionsByDistribution($distribution);

        foreach ($productDistributionArray as $productDistribution) {
            if (isset($productDistribution->product)) {
                $productDistributionArray[$productDistribution->id_product] = [
                    'active' => (int) $productDistribution->active,
                    'unavailable' => (int) $productDistribution->product->unavailable,
                    'quantity_max' => $productDistribution->quantity_max,
                    'quantity_order' => $this->orderSolver->getProductQuantity($productDistribution->product, $orderArray),
                    'quantity_remaining' => $productDistribution->quantity_max - $this->orderSolver->getProductQuantity($productDistribution->product, $orderArray)
                ];
            }
        }

        return $productDistributionArray;
    }

    public function isCreditAutoPayment(Order $order, bool $debitCreditOnFunctioningOptional = false)
    {
        $pointSale = $order->pointSale;
        if($pointSale) {
            if($order->subscription && $pointSale->payment_method_credit) {
                if($order->subscription->auto_payment == Subscription::AUTO_PAYMENT_YES) {
                    return true;
                }

                if($order->subscription->auto_payment == Subscription::AUTO_PAYMENT_NO) {
                    return false;
                }
            }

            $creditFunctioning = $this->producerRepository->getPointSaleCreditFunctioning($pointSale);
            if ($order->id_user && $this->producerSolver->getConfig('credit') && $pointSale->payment_method_credit) {
                if($order->mean_payment == MeanPayment::CREDIT || $creditFunctioning == Producer::CREDIT_FUNCTIONING_MANDATORY) {
                    return true;
                }
                elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_OPTIONAL) {
                    return $debitCreditOnFunctioningOptional;
                }
                elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_USER) {
                    $userProducer = $this->userProducerRepository->findOneUserProducer($order->user);
                    if ($userProducer) {
                        return $userProducer->credit_active;
                    }
                }
            }
        }

        return false;
    }

    public function isCreditContext(Order $order)
    {
        if(!$this->producerSolver->getConfig('credit')) {
            return false;
        }

        //$pointSale = $this->pointSaleRepository->findOnePointSaleById($order->id_point_sale);
        $pointSale = $order->pointSale;

        if($pointSale) {
            $creditFunctioning = $this->producerRepository->getPointSaleCreditFunctioning($pointSale);
            if ($order->id_user && $this->producerSolver->getConfig('credit') && $pointSale->payment_method_credit) {
                if($order->mean_payment == MeanPayment::CREDIT
                    || $creditFunctioning == Producer::CREDIT_FUNCTIONING_MANDATORY
                    || $creditFunctioning == Producer::CREDIT_FUNCTIONING_OPTIONAL) {

                    return true;
                }
                elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_USER) {
                    $userProducer = $this->userProducerRepository->findOneUserProducer($order->user);
                    if ($userProducer) {
                        return $userProducer->credit_active;
                    }
                }
            }
        }

        return false;
    }

    public function findOneOrderLastByUser(User $user)
    {
        return $this->createDefaultQuery()
            ->filterByUser($user)
            ->orderBy('order.id DESC')
            ->findOne();
    }

    /**
     * Retourne le point de vente favoris d'un utilisateur : le point de vente auquel le client est lié,
     * le point de vente de la dernière commande sinon.
     */
    public function getUserFavoritePointSale(User $user, Distribution $distribution = null): ?PointSale
    {
        $pointSale = null;
        $arrayUserPointSale = $this->userPointSaleRepository->findUserPointSalesByUser($user, $distribution);

        if (count($arrayUserPointSale) == 1 && $arrayUserPointSale[0]->id_point_sale) {
            $pointSale = $this->pointSaleRepository->findOnePointSaleById($arrayUserPointSale[0]->id_point_sale);
        } else {
            $lastOrder = $this->findOneOrderLastByUser($user);
            if ($lastOrder) {
                $pointSale = $this->pointSaleRepository->findOnePointSaleById($lastOrder->id_point_sale);
                if($distribution && $pointSale && !$this->pointSaleSolver->isDelivered($pointSale, $distribution)) {
                    $pointSale = null;
                }
            }
        }

        return $pointSale;
    }

    public function getTurnoverByDate(\DateTime $date)
    {
        return $this->getTurnoverByDateStartEnd(
            $date->modify('first day of this month'),
            $date->modify('last day of this month')
        );
    }

    public function getTurnoverLastThirtyDays()
    {
        $today = new \DateTime();
        $thirtyDaysBefore = (clone $today)->modify('-30 days');

        return $this->getTurnoverByDateStartEnd(
            $thirtyDaysBefore,
            $today
        );
    }

    public function getTurnoverByDateStartEnd(\DateTime $dateStart, \DateTime $dateEnd)
    {
        $res = \Yii::$app->db->createCommand("SELECT SUM(product_order.price * product_order.quantity) AS total
                    FROM `order`, product_order, distribution
                    WHERE `order`.id_distribution = distribution.id
                    AND `order`.id = product_order.id_order
                    AND distribution.date >= :date_start
                    AND distribution.date <= :date_end
                ")
            ->bindValue(':date_start', $dateStart->format('Y-m-d'))
            ->bindValue(':date_end', $dateEnd->format('Y-m-d'))
            ->queryOne();

        if ($res['total']) {
            return $res['total'];
        } else {
            return 0;
        }
    }

    public function getAverageTurnoverLastThreeMonths()
    {
        $total = 0;
        $date = new \DateTime();

        for($i = 0; $i < 3; $i++) {
            $date->modify('-1 month');
            $total += $this->getTurnoverByDate($date);
        }

        return intval($total / 3);
    }

    public function findOrdersIncomingBySubscription(Subscription $subscription, bool $begin = true)
    {
        if($begin) {
            $dateStart = $subscription->date_begin;
            $comparatorDateStart = '>=';
        }
        else {
            $dateStart = $subscription->date_end;
            $comparatorDateStart = '>';
        }

        $params = [
            ':id_producer' => GlobalParam::getCurrentProducerId(),
            ':date_today' => date('Y-m-d'),
            ':date_start' => $dateStart,
            ':id_subscription' => $subscription->id
        ];

        $orders = Order::find()
            ->joinWith('distribution')
            ->where('distribution.id_producer = :id_producer')
            ->andWhere('distribution.date >= :date_today')
            ->andWhere('distribution.date ' . $comparatorDateStart . ' :date_start')
            ->andWhere('order.id_subscription = :id_subscription')
            ->andWhere(OrderRepositoryQuery::getSqlFilterIsValid());

        $orders->params($params);

        return $orders->all();
    }


    public function isOrderPaid(Order $order): bool
    {
        $amountPaid = $this->orderSolver->getOrderAmount($order, Order::AMOUNT_PAID);
        $amountTotal = $this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL);

        if(abs($amountPaid - $amountTotal) < 0.00001
            || $amountPaid >= $amountTotal) {
            return true;
        }

        return $this->isOrderPaidViaInvoice($order);
    }

    public function isOrderPaidViaInvoice(Order $order): bool
    {
        if($order->invoice) {
            $invoice = $this->invoiceRepository->findOneInvoiceById($order->id_invoice);
            if($invoice && $this->invoiceSolver->isInvoicePaid($invoice)) {
                return true;
            }
        }

        return false;
    }

    public function getMainPayment(Order $order): ?Payment
    {
        foreach($order->payment as $payment) {
            if($this->paymentSolver->isTypeDebit($payment)) {
                return $payment;
            }
        }

        return null;
    }

    public function getPaymentLabelShort(Order $order, string $context = 'admin'): string
    {
        $isOrderPaid = $this->isOrderPaid($order);
        $amountPaid = $this->orderSolver->getOrderAmountPaid($order);
        $amountTotal = $this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL);
        $label = '&nbsp;';
        $classLabel = 'default';
        $titleLabel = '';

        if($amountPaid > -0.01 && $amountPaid < 0.01) {
            if($isOrderPaid && $amountTotal != 0) {
                $label = 'Facture payée';
            }
            elseif($this->isCreditAutoPayment($order) && $amountTotal != 0) {
                if($order->subscription && $order->subscription->auto_payment == 0) {
                    $label = 'Cagnotte désactivée';
                }
                else {
                    $label = 'Cagnotte non débitée';
                }
            }
            elseif($amountTotal == 0) {
                $label = 'Gratuit';
            }
            else {
                $label = ($context == 'admin') ? 'Non réglé' : '';
            }
        }
        else {
            $mainPayment = $this->getMainPayment($order);
            if($mainPayment) {
                if($this->paymentSolver->isMeanPaymentCredit($mainPayment)) {
                    $label = 'Cagnotte débitée';
                }
                else {
                    $label = MeanPayment::getStrBy($mainPayment->mean_payment);
                }
            }
        }

        $orderPaymentStatus = $this->orderSolver->getPaymentStatus($order);
        if($amountPaid > -0.01 && $amountPaid < 0.01 && !$isOrderPaid) {
            $classLabel = ($context == 'admin') ? 'default' : 'secondary';
        }
        elseif($orderPaymentStatus == Order::PAYMENT_SURPLUS) {
            $classLabel = 'warning';
            $titleLabel = 'Paiement en surplus';
        }
        elseif(($isOrderPaid && $amountTotal != 0) || $amountTotal == 0) {
            $classLabel = 'success';
        }
        elseif($orderPaymentStatus == Order::PAYMENT_UNPAID) {
            $classLabel = 'warning';
            $titleLabel = 'Paiement partiel '.$amountPaid;
        }

        $prefixClassLabel = ($context == 'admin') ? 'label label-' : 'small text-';

        $labelHtml = '<span class="'.$prefixClassLabel . $classLabel.'" title="'.$titleLabel.'">'.$label.'</span>';

        if($amountPaid) {
            $labelHtml .= $this->orderSolver->getPaymentLabelAmountRemainingSurplus($order);
        }

        return $labelHtml;
    }

    public function getPaymentLabelPaid(Order $order): string
    {
        $isOrderPaid = $this->isOrderPaid($order);
        $amountPaid = $this->orderSolver->getOrderAmountPaid($order);
        $amountTotal = $this->orderSolver->getOrderAmountWithTax($order, Order::AMOUNT_TOTAL);
        $label = '';

        if($amountPaid > -0.01 && $amountPaid < 0.01) {
            if ($isOrderPaid && $amountTotal != 0) {
                $label = 'Facture payée';
            }
        }
        else {
            $mainPayment = $this->getMainPayment($order);
            if($mainPayment) {
                if($this->paymentSolver->isMeanPaymentCredit($mainPayment)) {
                    $label = 'Cagnotte débitée';
                }
                else {
                    $strMeanPayment = strtolower(MeanPayment::getStrBy($mainPayment->mean_payment));
                    if(in_array($mainPayment->mean_payment, [MeanPayment::CHEQUE, MeanPayment::CREDIT_CARD, MeanPayment::TRANSFER])) {
                        $label = 'Payé par '.$strMeanPayment;
                    }
                    elseif($mainPayment->mean_payment == MeanPayment::MONEY) {
                        $label = 'Payé en '.$strMeanPayment;
                    }
                    elseif($mainPayment->mean_payment == MeanPayment::OTHER) {
                        $label = 'Payé ('.$strMeanPayment.')';
                    }
                }

                $label .= $this->orderSolver->getPaymentLabelAmountRemainingSurplus($order);
            }
        }

        return $label;
    }

    public function isOrderCreditFunctioningMandatory(Order $order): bool
    {
        $pointSale = $order->pointSale;
        return $pointSale && $pointSale->payment_method_credit && $pointSale->credit_functioning == Producer::CREDIT_FUNCTIONING_MANDATORY;
    }

    public function isOrderCreditFunctioningUser(Order $order): bool
    {
        if($order->user) {

            $pointSale = $order->pointSale;

            // @TODO : à optimiser
            $userProducer = $this->userProducerRepository->findOneUserProducer($order->user);

            return $pointSale
                && $pointSale->payment_method_credit
                && $pointSale->credit_functioning == Producer::CREDIT_FUNCTIONING_USER
                && $userProducer
                && $userProducer->credit_active;
        }

        return false;
    }

    public function findOrdersDashboard(): array
    {
        $optionDashboardDateStart = $this->producerSolver->getConfig('option_dashboard_date_start');
        $optionDashboardDateEnd = $this->producerSolver->getConfig('option_dashboard_date_end');

        $paramsOrders = [];
        if ($optionDashboardDateStart || $optionDashboardDateEnd) {
            $conditionsOrders = '';
            if ($optionDashboardDateStart) {
                $conditionsOrders .= 'distribution.date >= :date_start';
                $paramsOrders[':date_start'] = $optionDashboardDateStart;
            }
            if ($optionDashboardDateEnd) {
                if ($optionDashboardDateStart) {
                    $conditionsOrders .= ' AND ';
                }
                $conditionsOrders .= 'distribution.date <= :date_end';
                $paramsOrders[':date_end'] = $optionDashboardDateEnd;
            }
        } else {
            $conditionsOrders = 'distribution.date >= :date_start';
            $paramsOrders[':date_start'] = date('Y-m-d 00:00:00');
        }

        $conditionsOrders .= ' AND '.OrderRepositoryQuery::getSqlFilterIsOrderStatusNotDeleted();

        $ordersArray = Order::searchAll([], [
            'orderby' => 'IF(ISNULL(date_update), `order`.`date`, `order`.`date_update`) DESC',
            'conditions' => $conditionsOrders . ' AND (origin = \'' . Order::ORIGIN_USER . '\' OR origin = \'' . Order::ORIGIN_ADMIN . '\' OR (origin = \'' . Order::ORIGIN_AUTO . '\' AND date_update IS NOT NULL))',
            'params' => $paramsOrders,
        ]);

        return $ordersArray;
    }

    public function countOrdersByUser(User $user)
    {
        return Order::searchCount([
            'id_user' => $user->id,
        ], [
            'conditions' => OrderRepositoryQuery::getSqlFilterIsValid()
        ]);
    }

    public function getTotalAmountSpent(User $user): float
    {
        $orderBuilder = OrderBuilder::getInstance();
        $totalAmountSpent = 0;
        $ordersArray = $this->findOrdersByUser($user);
        foreach($ordersArray as $order) {
            $orderBuilder->initOrder($order);
            $totalAmountSpent += $this->orderSolver->getOrderAmountWithTax($order);
        }

        return $totalAmountSpent;
    }

    public function getAverageBasketByUser(User $user): ?float
    {
        $countOrders = $this->countOrdersByUser($user);
        $totalAmountSpent = $this->getTotalAmountSpent($user);

        if($countOrders && $totalAmountSpent) {
            return $totalAmountSpent / $countOrders;
        }

        return null;
    }
}