<?php

namespace Lc\CaracoleBundle\Solver\Price;

use Lc\CaracoleBundle\Model\Order\OrderReductionCreditInterface;
use Lc\CaracoleBundle\Model\Order\OrderShopInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCartModel;
use Lc\CaracoleBundle\Solver\Product\ProductFamilySolver;
use Lc\CaracoleBundle\Solver\Product\ProductSolver;

class OrderShopPriceSolver
{
    //TODO vérifier si les round sont cohérents
    use PriceSolverTrait;

    protected OrderProductPriceSolver $orderProductPriceResolver;
    protected ProductSolver $productSolver;
    protected ProductFamilySolver $productFamilySolver;

    public function __construct(
            OrderProductPriceSolver $orderProductPriceResolver,
            ProductSolver $productSolver,
            ProductFamilySolver $productFamilySolver
    ) {
        $this->orderProductPriceResolver = $orderProductPriceResolver;
        $this->productSolver = $productSolver;
        $this->productFamilySolver = $productFamilySolver;
    }

    //Inclus les ReductionCatalog des OrderProducts
    public function getTotalOrderProducts(OrderShopInterface $orderShop): float
    {
        // A tester calculer ce montant en faisant TotalOrderWithTax - TotalOrderTaxes

        $total = 0;
        foreach ($orderShop->getOrderProducts() as $orderProduct) {
            $total += $this->orderProductPriceResolver->getTotalWithReduction($orderProduct);
        }
        return  $this->round($total);
    }

    //Inclus les ReductionCatalog des OrderProducts
    public function getMarginOrderProducts(OrderShopInterface $orderShop): float
    {
        $total = 0;
        foreach ($orderShop->getOrderProducts() as $orderProduct) {
            $total += $this->orderProductPriceResolver->getTotalMargin($orderProduct);
        }
        return  $this->round($total);
    }

    public function getMarginOrderProductsWithReductions(OrderShopInterface $orderShop, $cache = false): float
    {
        if ($cache && $orderShop->getStatMarginOrderProductsWithReductions() !== null) {
            return $orderShop->getStatMarginOrderProductsWithReductions();
        } else {
            $total = $this->getMarginOrderProducts($orderShop);

            $totalReductionAmount = 0;
            foreach ($orderShop->getOrderReductionCarts() as $orderReductionCart) {
                $totalReductionAmount += $this->getOrderProductsReductionCartAmountWithoutTax(
                        $orderShop,
                        $orderReductionCart
                );
            }

            foreach ($orderShop->getOrderReductionCredits() as $orderReductionCredit) {
                $totalReductionAmount += $this->getOrderProductsReductionCreditAmountWithoutTax(
                        $orderShop,
                        $orderReductionCredit
                );
            }

            $total -= $totalReductionAmount;

            return  $this->round($total);
        }
    }

    public function getMarginOrderProductsWithReductionsPercent(OrderShopInterface $orderShop): float
    {
        if ($this->getTotalOrderProducts($orderShop)) {
            return $this->round(
                    $this->getMarginOrderProductsWithReductions(
                            $orderShop
                    ) / $this->getTotalOrderProductsWithReductions($orderShop) * 100
            );
        } else {
            return 0;
        }
    }

    public function getMarginOrderProductsPercent(OrderShopInterface $orderShop): float
    {
        if ($this->getTotalOrderProducts($orderShop)) {
            return $this->round(
                    $this->getMarginOrderProducts($orderShop) / $this->getTotalOrderProducts($orderShop) * 100
            );
        } else {
            return 0;
        }
    }

    public function getBrandTaxesOrderProductsWithReductionsPercent(OrderShopInterface $orderShop): float
    {
        if ($this->getTotalOrderProducts($orderShop)) {
            return $this->round(
                    $this->getMarginOrderProducts($orderShop) / $this->getTotalBuyingPriceOrderProducts(
                            $orderShop->getOrderProducts()
                    ) * 100
            );
        } else {
            return 0;
        }
    }

    public function getTotalOrderProductsWithTax(OrderShopInterface $orderShop): float
    {
        return $this->getTotalOrderProductsWithTaxByOrderProducts($orderShop->getOrderProducts());
    }

    public function getTotalBuyingPriceOrderProducts($orderProducts): float
    {
        $total = 0;

        foreach ($orderProducts as $orderProduct) {
            $total += $this->orderProductPriceResolver->getTotalBuyingPrice($orderProduct);
        }

        return $total;
    }

    public function getTotalBuyingPriceOrderProductsWithTax($orderProducts): float
    {
        $total = 0;

        foreach ($orderProducts as $orderProduct) {
            $total += $this->orderProductPriceResolver->getTotalBuyingPriceWithTax($orderProduct);
        }

        return  $this->round($total);
    }

    public function getTotalOrderProductsWithTaxByOrderProducts($orderProducts): float
    {
        $total = 0;
        foreach ($orderProducts as $orderProduct) {
            $total += $this->orderProductPriceResolver->getTotalWithTaxAndReduction($orderProduct);
        }

        return  $this->round($total);
    }

    public function getTotalOrderProductsTaxes(OrderShopInterface $orderShop): float
    {
        $total = 0;

        foreach ($orderShop->getOrderProducts() as $orderProduct) {
            $total += $this->orderProductPriceResolver->getTotalTaxes($orderProduct) / $this->getReductionsCoef(
                            $orderShop
                    );
        }

        return  $this->round($total);
    }

    public function getOrderProductsTaxesAsArray(OrderShopInterface $orderShop): array
    {
        $orderProductsTaxes = [];
        foreach ($orderShop->getOrderProducts() as $orderProduct) {
            $idTaxRate = $orderProduct->getTaxRate()->getId();

            if (!isset($orderProductsTaxes[$idTaxRate])) {
                $orderProductsTaxes[$idTaxRate] = [
                        'label' => $orderProduct->getTaxRate()->getValue() . '%',
                        'totalOrderProducts' => 0,
                        'totalTaxes' => 0,
                ];
            }

            $orderProductsTaxes[$idTaxRate]['totalOrderProducts'] +=  $this->round($this->orderProductPriceResolver->getTotalWithReduction(
                            $orderProduct
                    ) / $this->getReductionsCoef($orderShop));
            $orderProductsTaxes[$idTaxRate]['totalTaxes'] +=  $this->round($this->orderProductPriceResolver->getTotalTaxes(
                            $orderProduct
                    ) / $this->getReductionsCoef($orderShop));
        }

        return $orderProductsTaxes;
    }

    private function getReductionsCoef(OrderShopInterface $orderShop): float
    {
        return $this->getTotalOrderProducts($orderShop) / $this->getTotalOrderProductsWithReductions($orderShop);
    }

    private function getTaxRateAverage(OrderShopInterface $orderShop): float
    {
        return  $this->round($this->getTotalOrderProductsWithTax($orderShop) / $this->getTotalOrderProducts($orderShop));
    }

    public function getTotalOrderProductsWithReductions(OrderShopInterface $orderShop, $cache = false)
    {
        if ($cache && $orderShop->getStatTotalOrderProductsWithReductions() !== null) {
            return $orderShop->getStatTotalOrderProductsWithReductions();
        } else {
            $total = $this->getTotalOrderProducts($orderShop);
            $total -= $this->getTotalReductionCartsAmount($orderShop);
            $total -= $this->getTotalReductionCreditsAmount($orderShop);
            return  $this->round($total);
        }
    }

    public function getTotalOrderProductsWithReductionCarts(OrderShopInterface $orderShop)
    {
        $total = $this->getTotalOrderProducts($orderShop);
        $total -= $this->getTotalReductionCartsAmount($orderShop);
        return  $this->round($total);
    }

    public function getTotalReductionCartsAmount(OrderShopInterface $orderShop)
    {
        $totalReductionAmount = 0;
        foreach ($orderShop->getOrderReductionCarts() as $orderReductionCart) {
            $totalReductionAmount += $this->getOrderProductsReductionCartAmountWithoutTax(
                    $orderShop,
                    $orderReductionCart
            );
        }
        return  $this->round($totalReductionAmount);
    }

    public function getTotalReductionCreditsAmount(OrderShopInterface $orderShop)
    {
        $totalReductionAmount = 0;
        foreach ($orderShop->getOrderReductionCredits() as $orderReductionCredit) {
            $totalReductionAmount += $this->getOrderProductsReductionCreditAmountWithoutTax(
                    $orderShop,
                    $orderReductionCredit
            );
        }
        return  $this->round($totalReductionAmount);
    }

    public function getTotalOrderProductsWithTaxAndReductions(OrderShopInterface $orderShop, $cache = false)
    {
        if ($cache && $orderShop->getStatTotalOrderProductsWithTaxAndReductions() !== null) {
            return $orderShop->getStatTotalOrderProductsWithTaxAndReductions();
        } else {
            $total = $this->getTotalOrderProductsWithTax($orderShop);
            $total -= $this->getTotalReductionCartsAmountWithTax($orderShop);
            $total -= $this->getTotalReductionCreditsAmountWithTax($orderShop);
            return  $this->round($total);
        }
    }

    public function getTotalOrderProductsWithTaxAndReductionCarts(OrderShopInterface $orderShop)
    {
        $total = $this->getTotalOrderProductsWithTax($orderShop);
        $total -= $this->getTotalReductionCartsAmountWithTax($orderShop);
        return  $this->round($total);
    }

    public function getTotalReductionCartsAmountWithTax(OrderShopInterface $orderShop)
    {
        $totalReductionAmount = 0;
        foreach ($orderShop->getOrderReductionCarts() as $orderReductionCart) {
            $totalReductionAmount += $this->getOrderProductsReductionCartAmountWithTax($orderShop, $orderReductionCart);
        }
        return  $this->round($totalReductionAmount);
    }

    public function getTotalReductionCreditsAmountWithTax(OrderShopInterface $orderShop)
    {
        $totalReductionAmount = 0;
        foreach ($orderShop->getOrderReductionCredits() as $orderReductionCredit) {
            $totalReductionAmount += $this->getOrderProductsReductionCreditAmountWithTax(
                    $orderShop,
                    $orderReductionCredit
            );
        }
        return  $this->round($totalReductionAmount);
    }

    public function getOrderProductsReductionCartAmountWithoutTax(OrderShopInterface $order, $orderReductionCart)
    {
        $amount = 0;
        if ($orderReductionCart->getAppliedTo() === ReductionCartModel::APPLIED_TO_ORDER_PRODUCTS) {
            if ($orderReductionCart->getUnit() == 'percent') {
                $amount = $this->amountReductionByPercentValue(
                        $this->getTotalOrderProducts($order),
                        $orderReductionCart->getValue()
                );
            } else {
                if ($orderReductionCart->getUnit() == 'amount') {
                    if ($orderReductionCart->getBehaviorTaxRate() == 'tax-excluded') {
                        $amount = $orderReductionCart->getValue();
                    } else {
                        if ($orderReductionCart->getBehaviorTaxRate() == 'tax-included') {
                            $amount = $this->round($orderReductionCart->getValue() / $this->getTaxRateAverage($order));
                        }
                    }
                }
            }
        }
        return  $this->round($amount);
    }

    public function getOrderProductsReductionCartAmountWithTax(OrderShopInterface $order, $orderReductionCart)
    {
        $amount = 0;

        if ($orderReductionCart->getAppliedTo() === ReductionCartModel::APPLIED_TO_ORDER_PRODUCTS) {
            if ($orderReductionCart->getUnit() == 'percent') {
                $amount = $this->amountReductionByPercentValue(
                        $this->getTotalOrderProductsWithTax($order),
                        $orderReductionCart->getValue()
                );
            } elseif ($orderReductionCart->getUnit() == 'amount') {
                if ($orderReductionCart->getBehaviorTaxRate() == 'tax-excluded') {
                    $amount = $this->round($orderReductionCart->getValue() * $this->getTaxRateAverage($order));
                } elseif ($orderReductionCart->getBehaviorTaxRate() == 'tax-included') {
                    $amount = $orderReductionCart->getValue();
                }
            }
        }

        return $this->round($amount);
    }

    public function getOrderProductsReductionCreditAmountWithoutTax(
            OrderShopInterface $order,
            OrderReductionCreditInterface $orderReductionCredit
    ) {
        $amount = 0;
        if ($orderReductionCredit->getBehaviorTaxRate() == 'tax-excluded') {
            $amount = $orderReductionCredit->getValue();
        } else {
            if ($orderReductionCredit->getBehaviorTaxRate() == 'tax-included') {
                $amount = $this->round($orderReductionCredit->getValue() / $this->getTaxRateAverage($order));
            }
        }

        return  $this->round($amount);
    }

    public function getOrderProductsReductionCreditAmountWithTax(
            OrderShopInterface $order,
            OrderReductionCreditInterface $orderReductionCredit
    ) {
        $amountWithTax = 0;
        if ($orderReductionCredit->getBehaviorTaxRate() == 'tax-excluded') {
            $amountWithTax = $this->round($orderReductionCredit->getValue() * $this->getTaxRateAverage($order));
        } elseif ($orderReductionCredit->getBehaviorTaxRate() == 'tax-included') {
            $amountWithTax = $orderReductionCredit->getValue();
        }

        return  $this->round($amountWithTax);
    }

    public function getTotalReductions(OrderShopInterface $orderShop)
    {
        $total = 0;

        foreach ($orderShop->getOrderReductionCarts() as $orderReductionCart) {
            $total += $this->getOrderProductsReductionCartAmountWithoutTax($orderShop, $orderReductionCart);
        }

        foreach ($orderShop->getOrderReductionCredits() as $orderReductionCredit) {
            $total += $this->getOrderProductsReductionCreditAmountWithoutTax($orderShop, $orderReductionCredit);
        }

        return  $this->round($total);
    }

    public function getTotalReductionsWithTax(OrderShopInterface $orderShop)
    {
        $total = 0;

        foreach ($orderShop->getOrderReductionCarts() as $orderReductionCart) {
            $total += $this->getOrderProductsReductionCartAmountWithTax($orderShop, $orderReductionCart);
        }

        foreach ($orderShop->getOrderReductionCredits() as $orderReductionCredit) {
            $total += $this->getOrderProductsReductionCreditAmountWithTax($orderShop, $orderReductionCredit);
        }

        return  $this->round($total);
    }
}