<?php

namespace common\logic\Producer\Producer\Repository;

use common\helpers\Departments;
use common\helpers\GlobalParam;
use common\helpers\Price;
use common\logic\AbstractRepository;
use common\logic\Document\Document\Model\DocumentInterface;
use common\logic\Document\Document\Service\DocumentSolver;
use common\logic\PointSale\PointSale\Model\PointSale;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Producer\Producer\Service\ProducerSolver;
use common\logic\Producer\ProducerPriceRange\Repository\ProducerPriceRangeRepository;
use common\logic\User\User\Model\User;
use yii\helpers\Html;

class ProducerRepository extends AbstractRepository
{
    protected ProducerRepositoryQuery $query;
    protected ProducerPriceRangeRepository $producerPriceRangeRepository;
    protected ProducerSolver $producerSolver;
    protected DocumentSolver $documentSolver;

    public function loadDependencies(): void
    {
        $this->query = $this->loadService(ProducerRepositoryQuery::class);
        $this->producerPriceRangeRepository = $this->loadService(ProducerPriceRangeRepository::class);
        $this->producerSolver = $this->loadService(ProducerSolver::class);
        $this->documentSolver = $this->loadService(DocumentSolver::class);
    }

    /**
     * Retourne les options de base nécessaires à la fonction de recherche.
     *
     */
    public function getDefaultOptionsSearch(): array
    {
        return [
            'with' => ['taxRate'],
            'join_with' => [],
            'orderby' => 'name ASC',
            'attribute_id_producer' => 'id'
        ];
    }

    public function findOneProducerById(int $id)
    {
        return Producer::searchOne(['id' => $id]);
    }

    public function findOneProducerBySlug(string $slug)
    {
        return Producer::searchOne(['slug' => $slug]);
    }

    public function queryProducersActive()
    {
        return Producer::find()
            ->where([
                'active' => true,
            ])
            ->orderBy('name ASC');
    }

    /**
     * Retourne le compte producteur de démonstration.
     *
     */
    public function findOneProducerDemoAccount()
    {
        return Producer::find()->where('name LIKE \'Démo\'')->one();
    }

    /**
     * Retourne la liste des établissements pour l'initialisation d'une listesélective.
     */
    public static function populateProducerDropdown(): array
    {
        $producers = Producer::find()
            ->where([
                'active' => true,
            ])
            ->orderBy('postcode, city ASC')
            ->all();

        $departments = Departments::get();
        $dataProducers = [];
        $optionsProducers = [];

        foreach ($producers as $p) {
            $departmentCode = substr($p->postcode, 0, 2);
            if (!key_exists('d' . $departmentCode, $dataProducers) && isset($departments[$departmentCode])) {
                $dataProducers['d' . $departmentCode] = '<strong>' . $departments[$departmentCode] . '</strong>';
                $optionsProducers['d' . $departmentCode] = ['disabled' => true];
            }

            $dataProducers[$p->id] = '<span class="glyphicon glyphicon-lock"></span> ' . Html::encode(
                    $p->name
                ) . ' - ' . Html::encode($p->postcode) . ' ' . Html::encode(
                    $p->city
                ) . ' <span class="glyphicon glyphicon-lock"></span>';

            if (strlen($p->code)) {
                $optionsProducers[$p->id] = ['class' => 'lock'];
            }
        }

        return [
            'data' => $dataProducers,
            'options' => $optionsProducers
        ];
    }

    /**
     * Retourne le CA du producteur pour un mois donné
     */
    public function getTurnover(Producer $producer, string $period = '', bool $format = false)
    {
        if (!$period) {
            $period = date('Y-m');
        }

        $connection = \Yii::$app->getDb();
        $command = $connection->createCommand(
            '
            SELECT SUM(product_order.price * product_order.quantity) AS turnover
            FROM `order`, product_order, distribution, product
            WHERE `order`.id = product_order.id_order
            AND distribution.id_producer = :id_producer
            AND `order`.id_distribution = distribution.id
            AND product_order.id_product = product.id
            AND distribution.date > :date_begin
            AND distribution.date < :date_end',
            [
                ':date_begin' => date('Y-m-31', strtotime("-1 month", strtotime($period))),
                ':date_end' => date('Y-m-01', strtotime("+1 month", strtotime($period))),
                ':id_producer' => $producer->id
            ]
        );

        $result = $command->queryOne();
        $turnover = $result['turnover'];

        if ($format) {
            return number_format($turnover, 2) . ' €';
        } else {
            return $turnover;
        }
    }

    public function getAmountToBeBilledByMonth(Producer $producer, $month, bool $format = false)
    {
        $turnover = $this->getTurnover($producer, $month);
        return $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, $format);
    }

    public function getSummaryAmountsToBeBilled(Producer $producer, string $label, int $numberOfMonths = 1): string
    {
        $text = '';
        $numMonthCurrent = date('m');

        if ($numberOfMonths == 1
            || ($numberOfMonths == 3 && (in_array($numMonthCurrent, [1, 4, 7, 10])))
            || ($numberOfMonths == 6 && (in_array($numMonthCurrent, [1, 7])))) {

            for ($i = 1; $i <= $numberOfMonths; $i++) {
                $month = date('Y-m', strtotime('-' . $i . ' month'));
                $turnover = $this->getTurnover($producer, $month);

                if ($turnover) {
                    $isBold = $this->producerSolver->isBillingTypeClassic($producer) && !$producer->option_billing_permanent_transfer;
                    if ($isBold) $text .= '<strong>';
                    $text .= $this->producerPriceRangeRepository->getAmountToBeBilledByTurnover($turnover, true);
                    if ($isBold) $text .= '</strong>';
                    $text .= ' / ' . Price::format($turnover, 0);
                    $text .= '<br />';
                }
            }

            if (strlen($text)) {
                $text = $label . ' : <br />' . $text;
            }

        }

        return $text;
    }

    public function getAmountBilledLastMonth(Producer $producer): float
    {
        if ($this->producerSolver->isBillingTypeClassic($producer)) {
            $month = date('Y-m', strtotime('-1 month'));
            return $this->getAmountToBeBilledByMonth($producer, $month);
        } elseif ($this->producerSolver->isBillingTypeFreePrice($producer)) {
            return $producer->free_price;
        }

        return 0;
    }

    public function getOnlinePaymentMinimumAmount(): float
    {
        $onlinePaymentMinimumAmount = $this->getConfig('option_online_payment_minimum_amount');
        if (!$onlinePaymentMinimumAmount) {
            $onlinePaymentMinimumAmount = Producer::ONLINE_PAYMENT_MINIMUM_AMOUNT_DEFAULT;
        }

        return $onlinePaymentMinimumAmount;
    }

    /**
     * Retourne une configuration d'un producteur donné
     *
     */
    public function getConfig(string $config = '', int $idProducer = 0)
    {
        if (strlen($config)) {
            if (!$idProducer) {
                $idProducer = GlobalParam::getCurrentProducerId();
            }

            $producer = $this->findOneProducerById($idProducer);
            if ($producer) {
                return $producer->$config;
            }
        }

        return null;
    }

    /**
     * Retourne les établissements liés à l'utilisateur.
     */
    // getBookmarked
    public function findProducersBookmarked(User $user): array
    {
        $producers = (new \yii\db\Query())
            ->select('*')
            ->from(['user_producer', 'producer'])
            ->where('user_producer.id_producer = producer.id')
            ->andWhere(['user_producer.id_user' => $user->id])
            ->andWhere(['user_producer.active' => 1])
            ->all();

        return $producers;
    }

    public function getNameProducer(User $user): string
    {
        $producer = $this->findOneProducerById($user->id_producer);
        return $producer->name;
    }

    public function isDocumentDisplayOrders(DocumentInterface $document): bool
    {
        return ($this->documentSolver->getClass($document) == 'Invoice') ?
            $this->getConfig('document_display_orders_invoice') :
            $this->getConfig('document_display_orders_delivery_note');
    }

    /**
     * Retourne le mode de fonctionnement du crédit d'un point de vente.
     */
    // getCreditFunctioning
    public function getPointSaleCreditFunctioning(PointSale $pointSale): string
    {
        return strlen($pointSale->credit_functioning) > 0 ?
            $pointSale->credit_functioning :
            $this->getConfig('credit_functioning');
    }

    public function findProducersActive()
    {
        return Producer::find()->where(['producer.active' => 1])->with(['contact'])->all();
    }

    public function findProducers()
    {
        return Producer::find()->with(['contact'])->all();
    }
}