<?php

namespace common\logic\Distribution\Distribution\Export;

use common\helpers\Price;
use common\logic\AbstractGenerator;
use common\logic\Config\Unit\Service\UnitSolver;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Distribution\ProductDistribution\Repository\ProductDistributionRepository;
use common\logic\Document\Document\Service\DocumentSolver;
use common\logic\Order\Order\Model\Order;
use common\logic\Order\Order\Repository\OrderRepository;
use common\logic\Order\Order\Service\OrderBuilder;
use common\logic\Order\Order\Service\OrderSolver;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\PointSale\PointSale\Repository\PointSaleRepository;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Product\Product\Model\Product;
use common\logic\Product\Product\Repository\ProductRepository;
use common\logic\Product\Product\Service\ProductSolver;
use common\logic\User\User\Repository\UserRepository;
use kartik\mpdf\Pdf;

class DistributionReportPdfGenerator extends AbstractGenerator implements DistributionExportGeneratorInterface
{
    const LIMIT_PRODUCTS = 120;

    protected UnitSolver $unitSolver;
    protected OrderRepository $orderRepository;
    protected OrderBuilder $orderBuilder;
    protected ProductRepository $productRepository;
    protected ProductDistributionRepository $productDistributionRepository;
    protected PointSaleRepository $pointSaleRepository;
    protected OrderSolver $orderSolver;
    protected ProductSolver $productSolver;
    protected DocumentSolver $documentSolver;
    protected UserRepository $userRepository;

    public function loadDependencies(): void
    {
        $this->unitSolver = $this->loadService(UnitSolver::class);
        $this->orderRepository = $this->loadService(OrderRepository::class);
        $this->orderBuilder = $this->loadService(OrderBuilder::class);
        $this->productRepository = $this->loadService(ProductRepository::class);
        $this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class);
        $this->pointSaleRepository = $this->loadService(PointSaleRepository::class);
        $this->orderSolver = $this->loadService(OrderSolver::class);
        $this->productSolver = $this->loadService(ProductSolver::class);
        $this->documentSolver = $this->loadService(DocumentSolver::class);
        $this->userRepository = $this->loadService(UserRepository::class);
    }

    public function generate(Distribution $distribution, bool $save = false)
    {
        $producer = $this->getProducerContext();
        $ordersArray = $this->orderRepository->findOrdersByDistribution($distribution);
        $productsArray = $this->productRepository->findProductsByDistribution($distribution);
        $selectedProductsArray = $this->productDistributionRepository->findProductDistributionsByDistribution($distribution);
        $pointsSaleArray = $this->pointSaleRepository->findPointSales();
        foreach ($pointsSaleArray as $pointSale) {
            $this->orderBuilder->initPointSaleOrders($pointSale, $ordersArray);
        }
        $isBig = count($productsArray) > self::LIMIT_PRODUCTS;

        if ($producer->slug == 'bourlinguepacotille') {
            $viewPdf = '@backend/views/distribution/report-bourlingue';
            $orientationPdf = Pdf::ORIENT_LANDSCAPE;
            $content = \Yii::$app->getView()->render($viewPdf, [
                'date' => $distribution->date,
                'distribution' => $distribution,
                'selectedProductsArray' => $selectedProductsArray,
                'pointsSaleArray' => $pointsSaleArray,
                'productsArray' => $productsArray,
                'ordersArray' => $ordersArray,
                'producer' => $producer
            ]);
        }
        else {
            $orientationPdf = Pdf::ORIENT_PORTRAIT;
            $content = $this->buildReportHtml($pointsSaleArray, $productsArray, $ordersArray, $isBig);
        }

        $pdf = new Pdf([
            'mode' => Pdf::MODE_UTF8,
            'format' => Pdf::FORMAT_A4,
            'orientation' => $orientationPdf,
            'destination' => $save ? Pdf::DEST_FILE : Pdf::DEST_BROWSER,
            'filename' => \Yii::getAlias(
                '@app/web/pdf/Commandes-' . $distribution->date . '-' . $this->getProducerContextId() . '.pdf'
            ),
            'content' => $content,
            //'cssFile' => Yii::getAlias('@web/css/distribution/report.css'),
            'cssInline' => '
                        table {
                            border-spacing : 0px ;
                            border-collapse : collapse ;
                            width: 100% ;
                        }
                        
                        table tr th,
                        table tr td {
                            padding: 0px ;
                            margin: 0px ;
                            border: solid 1px #e0e0e0 ;
                            padding: 3px 8px ;
                            vertical-align : top;
                            page-break-inside: avoid !important;
                            color: black;
                        }

                        table tr th { 
                            font-size: 13px ;
                        }

                        table tr td { 
                            font-size: 13px ;
                        }
                    ',
            'methods' => [
                'SetHeader' => ['Commandes du ' . date('d/m/Y', strtotime($distribution->date))],
                'SetFooter' => ['{PAGENO}'],
            ]
        ]);

        return $pdf->render();
    }

    public function buildReportHtml(array $pointsSaleArray, array $productsArray, array $ordersArray, bool $isBig): string
    {
        $html = $this->buildReportPointsSaleHtml($pointsSaleArray, $productsArray, $isBig);
        $html .= $this->buildReportPointsSaleTotalHtml($pointsSaleArray, $productsArray, $ordersArray, $isBig);
        return $html;
    }

    public function buildReportPointsSaleHtml(array $pointsSaleArray, array $productsArray, bool $isBig): string
    {
        $producer = $this->getProducerContext();
        $html = '' ;
        foreach ($pointsSaleArray as $pointSale) {
            if (count($pointSale->orders)) {

                $html .= '<h3>'.$pointSale->name.'</h3>' ;
                $columnDeliveryNote = ($producer->option_export_display_column_delivery_note) ? '<th>BL</th>' : '';
                $colCredit = ($pointSale->credit) ? '<th>Crédit</th>' : '' ;

                $html .= '<table class="">'
                    . '<thead>'
                    . '<tr>'
                    . '<th>Client</th>'
                    . '<th>Produits</th>'
                    . ($isBig ? '<th>Produits</th>' : '')
                    . '<th>Commentaire</th>'
                    . $columnDeliveryNote
                    . $colCredit
                    . '<th>Montant</th>'
                    . '</tr>'
                    . '</thead>'
                    . '<tbody>';

                foreach ($pointSale->orders as $order) {
                    $html .= '<tr>' ;
                    $html .= $this->columnUsername($order);
                    $html .= $this->columnOrderProducts($order, $productsArray);
                    $html .= $this->columnIfIsBig($isBig);
                    $html .= $this->columnComment($order);
                    $html .= $this->columnDeliveryNote($order);
                    $html .= $this->columnCredit($order, $pointSale);
                    $html .= $this->columnOrderAmount($order);
                    $html .= '</tr>' ;
                }

                $html .= '<tr><td><strong>Total</strong></td>' ;

                $strProducts = '';
                $cpt = 0 ;
                foreach ($productsArray as $product) {
                    foreach( Product::$unitsArray as $unit => $dataUnit) {
                        $quantity = $this->orderSolver->getProductQuantity($product, $pointSale->orders, false, $unit);
                        if ($quantity) {
                            $strProducts .= $this->displayOrderProduct($quantity, $unit, $product);
                        }
                    }

                    if($isBig && $cpt == self::LIMIT_PRODUCTS) {
                        $strProducts .= '</td><td>' ;
                    }

                    $cpt ++ ;
                }

                $html .= '<td>'.$strProducts.'</td><td></td>' ;
                if($pointSale->credit) {
                    $html .= '<td></td>' ;
                }
                if($producer->option_export_display_column_delivery_note) {
                    $html .= '<td></td>' ;
                }
                $html .= '<td><strong>'.Price::format($pointSale->revenues_with_tax) . '</strong></td>';

                $html .= '</tbody></table><pagebreak>' ;
            }
        }

        return $html;
    }

    public function columnUsername(Order $order): string
    {
        $producer = $this->getProducerContext();

        $strUser = $this->orderSolver->getOrderUsername($order) ;
        if(strlen($order->comment_point_sale))
        {
            $strUser .= '<br /><em>'.$order->comment_point_sale.'</em>' ;
        }

        if (isset($order->user) && strlen($order->user->phone)) {
            $strUser .= '<br />' . $order->user->phone . '';
        }

        if($producer->option_order_reference_type == Producer::ORDER_REFERENCE_TYPE_YEARLY && $order->reference && strlen($order->reference) > 0) {
            $strUser .= '<br />'.$order->reference ;
        }

        return '<td>'.$strUser.'</td>';
    }

    public function columnOrderProducts(Order $order, array $productsArray): string
    {
        $strProducts = '';
        foreach ($productsArray as $product) {
            foreach ($order->productOrder as $productOrder) {
                if($product->id == $productOrder->id_product) {
                    $strProducts .= $this->displayOrderProduct($productOrder->quantity, $productOrder->unit, $product);
                }
            }
        }

        return '<td>'.substr($strProducts, 0, strlen($strProducts) - 6).'</td>';
    }

    public function columnIfIsBig(bool $isBig): string
    {
        if($isBig) {
            return '<td></td>' ;
        }

        return '';
    }

    public function columnComment(Order $order): string
    {
        return '<td>'.$this->orderSolver->getCommentReport($order).'</td>';;
    }

    public function columnDeliveryNote(Order $order): string
    {
        $producer = $this->getProducerContext();
        if($producer->option_export_display_column_delivery_note) {
            $contentColumnDeliveryNote = '';
            if($order->deliveryNote) {
                if($this->documentSolver->isStatusDraft($order->deliveryNote)) {
                    $contentColumnDeliveryNote = 'Brouillon';
                }
                elseif($this->documentSolver->isStatusValid($order->deliveryNote)) {
                    $contentColumnDeliveryNote = 'Oui';
                }
            }
            return '<td>'.$contentColumnDeliveryNote.'</td>';
        }

        return '';
    }

    public function columnCredit(Order $order, PointSale $pointSale): string
    {
        if($pointSale->credit) {
            $credit = '' ;

            if(isset($order->user) && $order->user->id) {
                $credit = number_format($this->userRepository->getCredit($order->user, true),2).' €' ;
            }

            return '<td>'.$credit.'</td>' ;
        }

        return '';
    }

    public function columnOrderAmount(Order $order): string
    {
        $html = '<td><strong>'.number_format($order->amount_with_tax, 2) . ' €</strong>';

        $paymentLabelPaid = $this->orderRepository->getPaymentLabelPaid($order);
        if($paymentLabelPaid && strlen($paymentLabelPaid)) {
            $html .= '<br />'.$paymentLabelPaid;
        }

        /*if($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_PAID)
        {
            $html .= '(débité)' ;
        }
        elseif($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_UNPAID && $this->orderSolver->getOrderAmount($order, Order::AMOUNT_PAID))
        {
            $html .= '(reste '.$this->orderSolver->getOrderAmount($order, Order::AMOUNT_REMAINING, true).' à débiter)' ;
        }
        elseif($this->orderSolver->getPaymentStatus($order) == Order::PAYMENT_SURPLUS)
        {
            $html .= '(surplus : '.$this->orderSolver->getOrderAmount($order, Order::PAYMENT_SURPLUS, true).' à recréditer)' ;
        }*/

        $html .= '</td>' ;

        return $html;
    }

    public function buildReportPointsSaleTotalHtml(array $pointsSaleArray, array $productsArray, array $ordersArray, bool $isBig): string
    {
        $html = '';
        $html .= '<h3>Points de vente</h3>' ;
        $html .= '<table class="">'
            . '<thead>'
            . '<tr>'
            . '<th>Point de vente</th>'
            . '<th>Produits</th>'
            . ( $isBig ? '<th>Produits</th>' : '')
            . '<th>Montant</th>'
            . '</tr>'
            . '<tbody>';

        $revenues = 0 ;
        foreach ($pointsSaleArray as $pointSale)
        {
            if (count($pointSale->orders))
            {
                $html .= '<tr><td>'.$pointSale->name.'</td><td>' ;

                $cpt = 0 ;
                foreach ($productsArray as $product) {
                    foreach( Product::$unitsArray as $unit => $dataUnit) {
                        $quantity = $this->orderSolver->getProductQuantity($product, $pointSale->orders, false, $unit);
                        if ($quantity) {
                            $html .= $this->displayOrderProduct($quantity, $unit, $product);
                        }
                    }

                    if($isBig && $cpt == self::LIMIT_PRODUCTS) {
                        $html .= '</td><td>' ;
                    }

                    $cpt ++ ;
                }

                $html .= '</td><td>'.Price::format($pointSale->revenues_with_tax, 2).'</td></tr>' ;
                $revenues += $pointSale->revenues_with_tax ;
            }
        }

        // total
        $html .= '<tr><td><strong>Total</strong></td><td>' ;

        $cpt = 0 ;
        foreach ($productsArray as $product) {
            foreach( Product::$unitsArray as $unit => $dataUnit) {
                $quantity = $this->orderSolver->getProductQuantity($product, $ordersArray, false, $unit);
                if ($quantity) {
                    $html .= $this->displayOrderProduct($quantity, $unit, $product);
                }
            }
            if($isBig && $cpt == self::LIMIT_PRODUCTS) {
                $html .= '</td><td>' ;
            }

            $cpt ++ ;
        }

        $html .= '</td><td><strong>'.number_format($revenues, 2).' €</strong></td></tr>' ;

        $html .= '</tbody></table>' ;

        return $html;
    }

    public function displayOrderProduct(string $quantity, string $unit, Product $product)
    {
        $theUnit = ( $this->unitSolver->strUnit($unit, 'wording_short', true) == 'p.') ? '' : '&nbsp;'. $this->unitSolver->strUnit($unit, 'wording_short', true) ;
        return '<strong>'.$quantity. $theUnit.'</strong> '.$this->productSolver->getNameExport($product). '<br />';
    }
}