<?php

namespace common\logic\Distribution\Distribution\Repository;

use common\helpers\GlobalParam;
use common\logic\AbstractRepository;
use common\logic\Distribution\Distribution\Model\Distribution;
use common\logic\Distribution\Distribution\Service\DistributionSolver;
use common\logic\Producer\Producer\Model\Producer;
use common\logic\Subscription\Subscription\Model\Subscription;
use common\logic\Subscription\Subscription\Service\SubscriptionSolver;

class DistributionRepository extends AbstractRepository
{
    protected DistributionRepositoryQuery $query;
    protected DistributionSolver $distributionSolver;
    protected SubscriptionSolver $subscriptionSolver;

    public function loadDependencies(): void
    {
        $this->query = $this->loadService(DistributionRepositoryQuery::class);
        $this->distributionSolver = $this->loadService(DistributionSolver::class);
        $this->subscriptionSolver = $this->loadService(SubscriptionSolver::class);
    }

    public function getDefaultOptionsSearch(): array
    {
        return [
            'with' => [],
            'join_with' => [],
            'orderby' => 'date ASC',
            'attribute_id_producer' => 'distribution.id_producer'
        ];
    }

    public function findOneDistributionById(int $id): ?Distribution
    {
        return Distribution::searchOne([
            'id' => $id
        ]);
    }

    public function findOneDistribution(string $date, bool $active = null): ?Distribution
    {
        $paramsDistribution = [
            'date' => $date,
            'distribution.id_producer' => $this->getProducerContext()->id
        ];

        if(!is_null($active)) {
            $paramsDistribution['active'] = $active;
        }

        return Distribution::searchOne($paramsDistribution);
    }

    public function findOneDistributionByDate(string $date): ?Distribution
    {
        return Distribution::searchOne([
            'distribution.date' => $date
        ]);
    }

    public function findOneFirstDistribution(): ?Distribution
    {
        return Distribution::searchOne([], [
            'orderby' => 'date ASC'
        ]);
    }

    public function findOneLastDistribution(): ?Distribution
    {
        return Distribution::searchOne([], [
            'orderby' => 'date DESC'
        ]);
    }

    public function findDistributionsActive(): array
    {
        return Distribution::searchAll([
            'active' => 1
        ], [
            'orderby' => 'date ASC',
        ]);
    }

    /**
     * Récupère les distributions futures.
     */
    public function findDistributionsIncoming(): array
    {
        $distributionsArray = Distribution::find()
            ->where('date > \'' . date('Y-m-d') . '\'')
            ->andWhere([
                'id_producer' => GlobalParam::getCurrentProducerId(),
                'active' => 1
            ])
            ->orderBy('date ASC')
            ->all();

        return $distributionsArray;
    }

    /**
     * Recherche les distributions futures où l'abonnement peut s'appliquer.
     */
    // searchMatchedIncomingDistributions
    public function findDistributionsIncomingMatchWithSubscrtiption(Subscription $subscription): array
    {
        $params = [
            ':date_earliest_order' => date('Y-m-d'),
            ':date_begin' => date('Y-m-d', strtotime($subscription->date_begin)),
            ':id_producer' => GlobalParam::getCurrentProducerId()
        ];

        $incomingDistributions = Distribution::find()
            ->where('id_producer = :id_producer')
            ->andWhere('date >= :date_begin')
            ->andWhere('date > :date_earliest_order');

        if ($subscription->date_end) {
            $incomingDistributions->andWhere('date <= :date_end');
            $params[':date_end'] = date('Y-m-d', strtotime($subscription->date_end));
        }

        $incomingDistributions->orderBy('date ASC');

        $incomingDistributions->params($params);
        $incomingDistributionsArray = $incomingDistributions->all();
        $this->distributionSolver->filterDistributionsByDateDelay($incomingDistributionsArray);

        $matchedIncomingDistributionsArray = [];
        foreach ($incomingDistributionsArray as $incomingDistribution) {
            if ($this->subscriptionSolver->isSubscriptionMatchWith($subscription, $incomingDistribution->date)) {
                $matchedIncomingDistributionsArray[] = $incomingDistribution;
            }
        }

        return $matchedIncomingDistributionsArray;
    }

    // isDateAvailable
    public function isDistributionDateAvailable(string $date = null): bool
    {
        if($date && strlen($date)) {
            $distribution = $this->findOneDistribution($date);
            if($distribution && $this->distributionSolver->isDistributionAvailable($distribution)) {
                return true;
            }
        }
        
        return false;
    }
}