<?php
declare(strict_types=1);
namespace Slivki\Response\Beauty\Offer\Factory;
use Slivki\Dao\Category\Rating\DirectorRatingDaoInterface;
use Slivki\Entity\BeautyMaster;
use Slivki\Entity\Category;
use Slivki\Entity\Director;
use Slivki\Entity\Offer;
use Slivki\Entity\PhoneNumber;
use Slivki\Enum\Beauty\MasterWorkPlaceType;
use Slivki\Response\Beauty\Offer\MasterLocationResponse;
use Slivki\Response\Beauty\Offer\MasterResponse;
use Slivki\Response\OnlineOrder\Director\DirectorResponse;
use Slivki\Services\ImageService;
use Slivki\Services\Offer\OfferCacheService;
use function array_map;
use function array_values;
use function count;
use function array_sum;
use function implode;
use function round;
final class MasterResponseFactory
{
private ImageService $imageService;
private DirectorRatingDaoInterface $directorRatingDao;
private OfferCacheService $offerCacheService;
private ?array $ratingDirectors = null;
public function __construct(
ImageService $imageService,
DirectorRatingDaoInterface $directorRatingDao,
OfferCacheService $offerCacheService
) {
$this->imageService = $imageService;
$this->directorRatingDao = $directorRatingDao;
$this->offerCacheService = $offerCacheService;
}
public function create(BeautyMaster $beautyMaster): MasterResponse
{
$ratingArray = [];
/** @var Category $category */
foreach ($beautyMaster->getCategories() as $category) {
if ($category->getSubCategories()->count() > 0) {
continue;
}
$ratingArray[] = $this->getRating($category->getID(), $beautyMaster->getDirector());
}
$rating = 0;
if (count($ratingArray) > 0) {
$rating = array_sum($ratingArray) / count($ratingArray);
}
return $this->createResponse($beautyMaster, $rating);
}
public function createForCategory(BeautyMaster $beautyMaster, int $categoryId): MasterResponse
{
return $this->createResponse(
$beautyMaster,
$this->getRating($categoryId, $beautyMaster->getDirector()),
);
}
private function createResponse(BeautyMaster $beautyMaster, float $rating): MasterResponse
{
$director = $beautyMaster->getDirector();
$locations = [];
$offerIds = [];
$categoryIds = [];
foreach ($beautyMaster->getLocations() as $location) {
$locations[] = new MasterLocationResponse(
$location->getId(),
implode(', ', [$location->getCity(), $location->getStreet(), $location->getHouse()]),
array_map(
static fn (PhoneNumber $phoneNumber) => $phoneNumber->getNumber(),
$location->getPhoneNumbers()->toArray(),
),
null === $location->getLatitude() ? null : (float) $location->getLatitude(),
null === $location->getLongitude() ? null : (float) $location->getLongitude(),
);
$firstOffer = $location->firstOffer();
if ($firstOffer->isActive()) {
$locationId = $firstOffer->getID();
$offerIds[$locationId] = $locationId;
}
}
foreach ($beautyMaster->getCategories() as $category) {
$categoryIds[] = $category->getID();
}
[$telegram, $viber] = $this->getSocial($beautyMaster, $offerIds);
return new MasterResponse(
$beautyMaster->getId(),
MasterWorkPlaceType::getByStatus($beautyMaster->getStatus()),
$beautyMaster->getFirstName(),
$beautyMaster->getLastName(),
$this->imageService->getImageURLCachedWithDomain($beautyMaster->getPhoto(), 0, 0),
$rating,
$beautyMaster->getDescription(),
$telegram,
$viber,
$beautyMaster->getSalon(),
$locations,
array_map(static fn (Category $tag) => $tag->getName(), $beautyMaster->getTags()->toArray()),
array_values($offerIds),
$director !== null
? new DirectorResponse(
$director->getID(),
$this->imageService->getImageURLCachedWithDomain($director->getOnlinePaymentLogo(), 0, 0),
$director->getName(),
$director->getLegalEntity(),
$director->getTaxID(),
)
: null,
array_values($categoryIds),
$beautyMaster->getOnlineOrderUrl(),
$beautyMaster->getLevel()
);
}
private function getSocial(BeautyMaster $beautyMaster, array $offerIds): array
{
$telegram = $beautyMaster->getTelegram();
$viber = $beautyMaster->getViber();
if ($telegram === null || $viber === null) {
foreach ($offerIds as $offerId) {
$offer = $this->offerCacheService->getOffer($offerId);
if ($offer instanceof Offer) {
if ($telegram === null) {
$telegram = $offer->getTelegram();
}
if ($viber === null) {
$viber = $offer->getViber();
}
break;
}
}
}
return [
empty($telegram) ? Offer::DEFAULT_TELEGRAM : $telegram,
empty($viber) ? Offer::DEFAULT_VIBER : $viber
];
}
private function getRating(int $categoryId, ?Director $director): float
{
if ($director === null) {
return 0;
}
if ($this->ratingDirectors === null) {
$this->ratingDirectors = $this->directorRatingDao->findDirectorRatingByCategoryId($categoryId);
}
foreach ($this->ratingDirectors as $ratingDirector) {
if ($ratingDirector->getDirectorId() === $director->getID()) {
return round($ratingDirector->getAvgCommentRating(), 2);
}
}
return 0;
}
}