<?php

namespace domain\PointSale\PointSale;

use domain\Distribution\Distribution\Distribution;
use domain\Producer\Producer\Producer;
use domain\User\User\User;
use domain\_\AbstractRepository;

class PointSaleRepository extends AbstractRepository
{
    protected PointSaleRepositoryQuery $query;

    public function loadDependencies(): void
    {
        $this->loadQuery(PointSaleRepositoryQuery::class);
    }

    public function getDefaultOptionsSearch(): array
    {
        return [
            self::WITH => [],
            self::JOIN_WITH => [],
            self::ORDER_BY => 'is_bread_box ASC, name ASC',
            self::ATTRIBUTE_ID_PRODUCER => 'point_sale.id_producer'
        ];
    }

    public function findOnePointSaleById(int $id): ?PointSale
    {
        return $this->createDefaultQuery()
            ->filterById($id)
            ->findOne();
    }

    public function findOnePointSaleByIdUser(int $idUser): ?PointSale
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->filterByIdUser($idUser)
            ->findOne();
    }

    public function findOnePointSaleByName(string $name): ?PointSale
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->filterByName($name)
            ->findOne();
    }

    public function queryPointSalesByDistribution(Distribution $distribution)
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->with(['pointSaleDistribution' => function ($q) use ($distribution) {
                $q->where(['id_distribution' => $distribution->id]);
            }]);
    }

    public function findPointSalesByDistribution(Distribution $distribution)
    {
        return $this->queryPointSalesByDistribution($distribution)->find();
    }

    public function findPointSalesByDistributionAsArray(Distribution $distribution)
    {
        return $this->queryPointSalesByDistribution($distribution)->asArray()->find();
    }

    public function findOnePointSaleDefaultByDistribution(Distribution $distribution): ?PointSale
    {
        $pointSalesArray = $this->findPointSalesByDistribution($distribution);
        foreach($pointSalesArray as $pointSale) {
            if($pointSale->default) {
                return $pointSale;
            }
        }

        return null;
    }

    /**
     * Retourne le nombre de points de vente pour le producteur courant.
     */
    public function countPointSales(): int
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->count();
    }

    public function findPointSales()
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->find();
    }

    public function findPointSalesByUserAccess(User $user)
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->filterByUserAccess($user)
            ->find();
    }

    public function countPointSalesPublic()
    {
        return $this->queryPointSalesPublic($this->getProducerContext())->count();
    }

    public function queryPointSalesPublic(Producer $producer)
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->filterByRestrictedAccess(0)
            ->orderBy('code ASC, restricted_access ASC, is_bread_box ASC, `default` DESC, name ASC')
            ->query();
    }

    public function populatePointSaleDropdownList(): array
    {
        $pointSalesArrayDropdown = ['' => '--'];
        $pointSalesArray = $this->findPointSales();

        foreach ($pointSalesArray as $pointSale) {
            $pointSalesArrayDropdown[$pointSale['id']] = $pointSale['name'];
        }

        return $pointSalesArrayDropdown;
    }

    public function findByBillingUser(User $user)
    {
        return $this->createDefaultQuery()
            ->filterIsOnline()
            ->filterByIdUser($user->id)
            ->orderBy('name ASC')
            ->find();
    }

    public function countPointSalesActiveLastThreeMonths()
    {
        $connection = \Yii::$app->getDb();
        $command = $connection->createCommand(
            '
            SELECT point_sale.id, COUNT(`order`.id) AS count_orders
            FROM `point_sale`
            LEFT JOIN `order` ON point_sale.id = `order`.id_point_sale AND `order`.`date` >= :date_limit
            GROUP BY point_sale.id
            HAVING count_orders > 0;',
            [
                ':date_limit' => date('Y-m-d', strtotime("-3 month")),
            ]
        );

        $results = $command->query();

        return count($results);
    }

    public function isDayOfWeekWithDelivery(string $dayWeek): bool
    {
        $activeDay = false;
        $pointsSaleArray = $this->findPointSales();
        $fieldDelivery = 'delivery_'.strtolower($dayWeek);

        foreach ($pointsSaleArray as $pointSale) {
            if ($pointSale->$fieldDelivery) {
                $activeDay = true;
            }
        }

        return $activeDay;
    }
}