<?php

namespace common\logic\Document\Document\Service;

use common\helpers\Price;
use common\logic\AbstractService;
use common\logic\Document\Document\Model\Document;
use common\logic\Document\Document\Model\DocumentInterface;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\ProductOrder\Service\ProductOrderSolver;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\SolverInterface;

class DocumentSolver extends AbstractService implements SolverInterface
{
    protected ProductOrderSolver $productOrderSolver;

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

    public function getAmount(DocumentInterface $document, string $type = Order::AMOUNT_TOTAL, bool $format = false)
    {
        return $this->_getAmountGeneric($document, $type, false, $format);
    }

    public function getAmountWithTax(DocumentInterface $document, string $type = Order::AMOUNT_TOTAL, bool $format = false)
    {
        return $this->_getAmountGeneric($document, $type, true, $format);
    }

    protected function _getAmountGeneric(DocumentInterface $document, string $type = Order::AMOUNT_TOTAL, bool $withTax = true, bool $format = false)
    {
        $amount = 0;
        $totalVat = 0;

        foreach($this->getProductsOrders($document) as $productOrderArray) {
            foreach($productOrderArray as $productOrder) {
                $priceLine = $this->productOrderSolver->getPriceByTypeTotal($productOrder, $type) * $productOrder->quantity;
                $amount += $priceLine;
                $totalVat += Price::getVat($priceLine, $productOrder->taxRate->value, $document->tax_calculation_method);
            }
        }

        if ($this->isTaxCalculationMethodRoundingOfTheSum($document)) {
            $totalVat = Price::round($totalVat);
        }

        if ($withTax) {
            $amount += $totalVat;
        }

        if ($format) {
            return Price::format($amount);
        } else {
            return $amount;
        }
    }

    public function getTotalVatArray(DocumentInterface $document, string $typeTotal): array
    {
        $totalVatArray = [];

        // Méthode de calcul via getProductOrders()
        foreach($this->getProductsOrders($document) as $productOrderArray) {
            foreach ($productOrderArray as $productOrder) {

                $idTaxRate = $productOrder->taxRate->id;
                if (!isset($totalVatArray[$idTaxRate])) {
                    $totalVatArray[$idTaxRate] = 0;
                }

                $totalVatArray[$idTaxRate] += Price::getVat(
                    $this->productOrderSolver->getPriceByTypeTotal($productOrder, $typeTotal) * $productOrder->quantity,
                    $productOrder->taxRate->value,
                    $document->tax_calculation_method
                );
            }
        }

        return $totalVatArray;
    }

    public function getPointSale(DocumentInterface $document): ?PointSale
    {
        if (isset($document->orders) && isset($document->orders[0])) {
            return $document->orders[0]->pointSale;
        }

        return null;
    }

    public function getDistribution(DocumentInterface $document)
    {
        if (isset($document->orders) && isset($document->orders[0])) {
            return $document->orders[0]->distribution;
        }

        return null;
    }

    public function isDocumentDeliveryNote(DocumentInterface $document): bool
    {
        return $this->getClass($document) == 'DeliveryNote';
    }

    public function isDocumentInvoice(DocumentInterface $document): bool
    {
        return $this->getClass($document) == 'Invoice';
    }

    public function isDocumentQuotation(DocumentInterface $document): bool
    {
        return $this->getClass($document) == 'Quotation';
    }

    public function getClass(DocumentInterface $document, bool $pathComplete = false): string
    {
        $classDocument = get_class($document);

        if(!$pathComplete) {
            return str_replace(
                [
                    'common\logic\Document\DeliveryNote\Model\\',
                    'common\logic\Document\Invoice\Model\\',
                    'common\logic\Document\Quotation\Model\\'],
                '',
                $classDocument);
        }

        return $classDocument;
    }

    public function getType(DocumentInterface $document): string
    {
        $class = $this->getClass($document);

        if ($class == 'Invoice') {
            $documentType = 'Facture';
        } elseif ($class == 'DeliveryNote') {
            $documentType = 'Bon de livraison';
        } elseif ($class == 'Quotation') {
            $documentType = 'Devis';
        }

        if (isset($documentType)) {
            return $documentType;
        }

        return '';
    }

    public function isValidClass(string $typeDocument): bool
    {
        return in_array($typeDocument, ['Invoice', 'DeliveryNote', 'Quotation']);
    }

    public function getStatusWording(DocumentInterface $document): string
    {
        return ($document->status == Document::STATUS_DRAFT) ? 'Brouillon' : 'Validé';
    }

    public function getStatusCssClass(DocumentInterface $document): string
    {
        return ($document->status == Document::STATUS_DRAFT) ? 'default' : 'success';
    }

    public function getHtmlLabel(DocumentInterface $document): string
    {
        $label = $this->getStatusWording($document);
        $classLabel = $this->getStatusCssClass($document);

        return '<span class="label label-' . $classLabel . '">' . $label . '</span>';
    }

    public function isStatus(DocumentInterface $document, string $status): bool
    {
        return $document->status == $status;
    }

    public function isStatusDraft(DocumentInterface $document): bool
    {
        return $this->isStatus($document, Document::STATUS_DRAFT);
    }

    public function isStatusValid(DocumentInterface $document): bool
    {
        return $this->isStatus($document, Document::STATUS_VALID);
    }

    public function getProductsOrders(DocumentInterface $document): array
    {
        $productsOrdersArray = [];
        $ordersArray = $document->orders;
        if ($ordersArray && count($ordersArray)) {
            foreach ($ordersArray as $order) {
                foreach ($order->productOrder as $productOrder) {
                    if ($productOrder->product) {
                        $indexProductOrder = $productOrder->product->order;
                        $newProductOrder = clone $productOrder;

                        if (!isset($productsOrdersArray[$indexProductOrder])) {
                            $productsOrdersArray[$indexProductOrder] = [$newProductOrder];
                        } else {
                            $productOrderMatch = false;
                            foreach ($productsOrdersArray[$indexProductOrder] as &$theProductOrder) {
                                if ($theProductOrder->unit == $productOrder->unit
                                    && $theProductOrder->price == $productOrder->price
                                    && $theProductOrder->invoice_price == $productOrder->invoice_price) {

                                    $theProductOrder->quantity += $productOrder->quantity;
                                    $productOrderMatch = true;
                                }
                            }
                            if (!$productOrderMatch) {
                                $productsOrdersArray[$indexProductOrder][] = $newProductOrder;
                            }
                        }
                    }
                }
            }
        }

        // tri des orderProduct par product.order
        ksort($productsOrdersArray);

        return $productsOrdersArray;
    }

    public function getAliasDirectoryBase(DocumentInterface $document): string
    {
        return '@app/web/pdf/' . $document->id_producer . '/';
    }

    public function getFilename(DocumentInterface $document): string
    {
        $filename = $this->getType($document) . '-';

        if($this->isStatusValid($document)) {
            $filename .= $document->reference;
        }
        elseif($this->isStatusDraft($document)) {
            $filename .= 'Brouillon-'.$document->id;
        }

        $filename .= '.pdf';

        return $filename;
    }

    public function getFilenameComplete(DocumentInterface $document): string
    {
        return \Yii::getAlias($this->getAliasDirectoryBase($document) . $this->getFilename($document));
    }

    public function isInvoicePrice(DocumentInterface $document): bool
    {
        return $this->getClass($document) == 'Invoice' || $this->getClass($document) == 'DeliveryNote';
    }

    public function isTaxCalculationMethodSumOfRoundings(DocumentInterface $document): bool
    {
        return $document->tax_calculation_method == Document::TAX_CALCULATION_METHOD_SUM_OF_ROUNDINGS;
    }

    public function isTaxCalculationMethodRoundingOfTheSum(DocumentInterface $document): bool
    {
        return $document->tax_calculation_method == Document::TAX_CALCULATION_METHOD_ROUNDING_OF_THE_SUM;
    }
}