<?php

namespace common\logic\Product\Product\Service;

use common\helpers\GlobalParam;
use common\helpers\Price;
use common\logic\AbstractService;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\Product\Product\Model\Product;
use common\logic\Product\ProductPrice\Service\ProductPriceSolver;
use common\logic\SolverInterface;

class ProductSolver extends AbstractService implements SolverInterface
{
    protected ProductPriceSolver $productPriceSolver;

    public function loadDependencies(): void
    {
        $this->productPriceSolver = $this->loadService(ProductPriceSolver::class);
    }

    public function getPrice(Product $product, array $params = []): ?float
    {
        $specificPriceArray = $product->productPrice;

        $user = (isset($params['user']) && $params['user']) ? $params['user'] : null;
        $pointSale = (isset($params['point_sale']) && $params['point_sale']) ? $params['point_sale'] : null;
        $quantity = (isset($params['quantity']) && $params['quantity']) ? $params['quantity'] : 1;
        //$userProducer = (isset($params['user_producer']) && $params['user_producer']) ? $params['user_producer'] : null;

        if ($specificPriceArray && ($user || $pointSale)) {
            $specificPriceArray = $this->productPriceSolver->filterByPriorityMatch(
                $specificPriceArray,
                $user,
                $pointSale
            );
            $bestPrice = 9999;
            foreach ($specificPriceArray as $specificPrice) {
                $fromQuantity = $specificPrice->from_quantity;
                if ((($fromQuantity && $fromQuantity <= $quantity) || !$fromQuantity)
                    && $specificPrice->price < $bestPrice) {
                    $bestPrice = $specificPrice->price;
                }
            }

            if ($bestPrice != 9999) {
                return $bestPrice;
            }
        }

        /*if ($userProducer && $userProducer->product_price_percent) {
            return $product->price * (1 + $userProducer->product_price_percent / 100);
        }*/

        /*if ($pointSale && $pointSale->product_price_percent) {
            return $product->price * (1 + $pointSale->product_price_percent / 100);
        }*/

        return $product->price;
    }

    /**
     * Retourne le prix du produit avec taxe
     */
    public function getPriceWithTax(Product $product, $params = [])
    {
        $taxRateValue = $product->taxRate ? $product->taxRate->value : 0;
        return Price::getPriceWithTax($this->getPrice($product, $params), $taxRateValue);
    }

    public function isAvailableOnPointSale(Product $product, PointSale $pointSale): bool
    {
        // disponible par défaut
        if ($product->available_on_points_sale) {
            foreach ($product->productPointSale as $productPointSale) {
                if (isset($pointSale->id)
                    && $productPointSale->id_point_sale
                    && $pointSale->id == $productPointSale->id_point_sale
                    && !$productPointSale->available) {
                    return false;
                }
            }

            return true;
        } // indisponible par défaut
        else {
            foreach ($product->productPointSale as $productPointSale) {
                if (isset($pointSale->id) && $pointSale->id == $productPointSale->id_point_sale
                    && $productPointSale->available) {
                    return true;
                }
            }

            return false;
        }
    }

    /**
     * Retourne la description du produit.
     */
    public function getDescription(Product $product): string
    {
        $description = $product->description;
        if (isset($product->weight) && is_numeric($product->weight) && $product->weight > 0) {
            if ($product->weight >= 1000) {
                $description .= ' (' . ($product->weight / 1000) . 'kg)';
            } else {
                $description .= ' (' . $product->weight . 'g)';
            }
        }

        return $description;
    }

    /**
     * Retourne le libellé (admin) du produit.
     */
    public function getStrWordingAdmin(Product $product): string
    {
        return $product->name;
    }

    public function getRefUnit(string $unit): string
    {
        if (isset(Product::$unitsArray[$unit]) && isset(Product::$unitsArray[$unit]['ref_unit'])) {
            return Product::$unitsArray[$unit]['ref_unit'];
        }

        return $unit;
    }

    /**
     * Retourne le libellé d'une unité.
     */
    public function strUnit(string $unit, $format = 'wording_short', $unitInDb = false): string
    {
        $strUnit = '';

        if ($unitInDb) {
            if ($unit == 'g') {
                $unit = 'kg';
            }
            if ($unit == 'mL') {
                $unit = 'L';
            }
        }

        if (isset(Product::$unitsArray[$unit]) && isset(Product::$unitsArray[$unit][$format])) {
            $strUnit = Product::$unitsArray[$unit][$format];
        }

        return $strUnit;
    }

    public function hasPriceWithQuantityZero(array $priceArray): bool
    {
        foreach ($priceArray as $price) {
            if ($price['from_quantity'] == 0) {
                return true;
            }
        }

        return false;
    }

    public function getTheTaxRate(Product $product)
    {
        if ($product->id_tax_rate) {
            return $product->id_tax_rate;
        } else {
            return GlobalParam::getCurrentProducer()->taxRate->id;
        }
    }

    public function getNameExport(Product $product)
    {
        $producer = GlobalParam::getCurrentProducer();
        if ($producer->option_export_display_product_reference
            && $product->reference
            && strlen($product->reference) > 0)
        {
            return $product->reference;
        }

        return $product->name;
    }
    
    public function isProductActiveByDay(Product $product, string $day): bool
    {
        return $product->active && $product->$day;
    }

    public function getProductFieldNameQuantityMax(string $day): string
    {
        return 'quantity_max_'.$day;
    }

    public function isProductQuantityMaxDefinedByDay(Product $product, string $day): bool
    {
        $fieldQuantityMax = $this->getProductFieldNameQuantityMax($day);
        return isset($product->$fieldQuantityMax) && $product->$fieldQuantityMax > 0;
    }

    public function getProductQuantityMaxByDay(Product $product, string $day): ?float
    {
        $quantityMax = $product->quantity_max;
        if($this->isProductQuantityMaxDefinedByDay($product, $day)) {
            $fieldQuantityMax = $this->getProductFieldNameQuantityMax($day);
            $quantityMax = $product->$fieldQuantityMax;
        }
        
        return $quantityMax;
    }
}