<?php
declare(strict_types=1);
namespace App\Controller\Frontend\Club;
use App\DBAL\Backend\EnumEstadoCompeticion;
use App\Entity\Backend\Agrupacion;
use App\Entity\Backend\Clasificado;
use App\Entity\Backend\Cliente;
use App\Entity\Backend\Club;
use App\Entity\Backend\Competicion;
use App\Entity\Backend\Comunidad;
use App\Entity\Backend\Equipo;
use App\Entity\Backend\Federacion;
use App\Entity\Backend\Inscrito;
use App\Entity\Backend\Jornada;
use App\Entity\Backend\Parcial;
use App\Entity\Backend\Resultado;
use App\Entity\Backend\Trazado;
use App\Entity\Gestion\Encuentro;
use Buzz\Browser;
use Buzz\Client\FileGetContents;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
final class ClubView extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $em
)
{
}
public function __invoke($id, $publi): Response|RedirectResponse
{
$club = $this->em->getRepository(Club::class)->findOneBy(array("id" => $id, "habilitado" => true));
if (!$club) {
$this->addFlash('error', "No encontramos el Club que nos ha solicitado");
return $this->redirect($this->generateUrl('provincias'));
}
list($defaultLogoGlobal, $defaultLogo) = $this->obtainDefaultLogo($id);
list($futures, $pastCompetitions) = $this->obtainCompetitions($id, $club);
$bestResults = array();
foreach ($pastCompetitions as $pastCompetition) {
if ($pastCompetition['grouping']) {
continue;
}
$competitionId = $pastCompetition['id'];
$bestResults[$competitionId] = $this->obtainBestResults($pastCompetition);
}
$courses = $this->em->getRepository(Trazado::class)->findBy(['club' => $id, 'activo' => 1], ['prioridad' => 'DESC', 'numero' => 'ASC']);
$weather = $this->obtainWeather($club);
return $this->render("frontend/Club/index-club.html.twig", [
'entity' => $club,
'publi' => $publi,
'defaultLogo' => $defaultLogo,
'defaultLogoGlobal' => $defaultLogoGlobal,
'futuras' => $futures,
'pasadas' => $pastCompetitions,
'tiempo' => $weather,
'trazados' => $courses,
'numElementos' => 6, //Numero de competiciones a mostrar por pagina de tab.
'bestResults' => $bestResults,
]);
}
private function obtainDefaultLogo($id): array
{
$defaultLogoGlobal = "https://resources.nextcaddy.com/clubResources/nextcaddy/logos/SVG/nextcaddy.svg";
$defaultLogo = $defaultLogoGlobal;
$prefix = strtoupper(substr($id, 0, 2));
$mapComunidad = [
"CM" => "Comunidad de Madrid",
"AM" => "Andalucia",
"77" => "Castilla y León",
"CP" => "Canarias",
];
$comunidadNombre = $mapComunidad[$prefix] ?? null;
if ($comunidadNombre) {
$comunidad = $this->em->getRepository(Comunidad::class)->findOneBy(["nombre" => $comunidadNombre]);
$defaultLogo = $comunidad?->getDefaultLogo() ?? $defaultLogoGlobal;
}
return array($defaultLogoGlobal, $defaultLogo);
}
private function obtainCompetitions($id, Club $club): array
{
$isFederation = !empty($this->em->getRepository(Federacion::class)->find($id));
$client = $club->getCliente();
$clientType = $client->getTipo();
$isClientTypeClub = "club" == $clientType;
$isClientTypeFederation = "federacion" == $clientType;
list($futureGroupings, $pastGroupings) = $this->addGroupings($client);
$total = 48;
$totalFuture = $total - count($futureGroupings);
$totalPast = $total - count($pastGroupings);
if ($isClientTypeClub || ($isClientTypeFederation && !$isFederation)) {
//Si es club me traigo sus alojadas
//Me traigo competiciones futuras y pasadas
// $futures = $this->em->getRepository(Competicion::class)->getCompeticiones($id, 36, 0, "mayor", "ASC", true);
// $pastCompetitions = $this->em->getRepository(Competicion::class)->getCompeticiones($id, 36, 0, "menor", "DESC", true);
$futureCompetitions = $this->em->getRepository(Competicion::class)->obtainFuturesCompetitionByClub($id, $totalFuture);
$pastCompetitions = $this->em->getRepository(Competicion::class)->obtainPastCompetitionByClub($id, $totalPast);
} else {
//Si es federacion o circuito buscamos sus organziadas
//Me traigo competiciones futuras y pasadas
// $futureCompetitions = $this->em->getRepository(Competicion::class)->getCompeticionesOrganizador($client->getNombreCorto(), 48, 0, "mayor", "ASC", true);
// $pastCompetitions = $this->em->getRepository(Competicion::class)->getCompeticionesOrganizador($client->getNombreCorto(), 48, 0, "menor", "DESC", true);
$organizer = $client->getNombreCorto();
$futureCompetitions = $this->em->getRepository(Competicion::class)->obtainFuturesCompetitionByOrganizer($organizer, $totalFuture);
$pastCompetitions = $this->em->getRepository(Competicion::class)->obtainPastCompetitionByOrganizer($organizer, $totalPast);
}
$futureCompetitions = $this->formatCompetitionData($futureCompetitions);
$pastCompetitions = $this->formatCompetitionData($pastCompetitions);
$futureCompetitions = array_merge($futureGroupings, $futureCompetitions);
$pastCompetitions = array_merge($pastGroupings, $pastCompetitions);
$futureCompetitions = $this->sortCompetitions($futureCompetitions);
$pastCompetitions = $this->sortCompetitions($pastCompetitions, true);
return array($futureCompetitions, $pastCompetitions);
}
private function obtainWeather(Club $club): array
{
//Id del municipio (según la Relación Española de Localidades en el INE)
$idAemet = ($club->getLocalidad()) ? $club->getLocalidad()->getIdAemet() : 0;
$tiempo = ['idAemet' => $idAemet,
'nombre' => "-",
'provincia' => "-",
'estado_cielo' => -1,
'prob_precipitacion' => "-",
'fecha' => "-",
'direccion' => "-",
'velocidad' => "-",
'maxima' => "-",
'minima' => "-"
];
if ($idAemet != 0) {
$client = new FileGetContents(new Psr17Factory());
$browser = new Browser($client, new Psr17Factory());
try {
$idAemet = strval($idAemet);
$response = $browser->get('https://www.aemet.es/xml/municipios/localidad_' . str_pad($idAemet, 5, "0", STR_PAD_LEFT) . '.xml');
} catch (\Throwable $e) {
$response = null;
}
if ((!is_null($response)) && ($response->getStatusCode() == 200)) {
$hoy = new \DateTime('now');
//Convertimos el XML a un array asociativo para manejarlo con comodidad
$data = $response->getBody();
$xml = simplexml_load_string(strval($data));
$json = json_encode($xml);
$array = json_decode($json, TRUE);
if (!empty($array)) {
$tiempo['nombre'] = $array['nombre']; //Nombre del municipio
$tiempo['provincia'] = $array['provincia']; //Nombre de la provincia
//Buscamos el día actual
foreach ($array['prediccion']['dia'] as $dia) {
if ($hoy->format('Y-m-d') == $dia['@attributes']['fecha']) {
$pos = 0;
if (($hoy->format('H') >= 0) && ($hoy->format('H') < 6)) {
$pos = 3;
} else if (($hoy->format('H') >= 6) && ($hoy->format('H') < 12)) {
$pos = 4;
} else if (($hoy->format('H') >= 12) && ($hoy->format('H') < 18)) {
$pos = 5;
} else if (($hoy->format('H') >= 18) && ($hoy->format('H') < 24)) {
$pos = 6;
}
//Arreglo para la lectura del XML que hay veces que la conversion es extraña y no coge bien el dato
if (is_array($dia['estado_cielo'][$pos]) && array_key_exists('@attributes', $dia['estado_cielo'][$pos])) { //Estado del cielo (un numero que indica el icono a usar para la previsión del día (de las 00h a las 24h) --> Decodificar dichos numeros
//Ahora mismo ignora los iconos de por la noche. Habría que añadirlos.
$tiempo['estado_cielo'] = str_replace("n", "", $dia['estado_cielo'][$pos][0]);
} else {
$tiempo['estado_cielo'] = str_replace("n", "", $dia['estado_cielo'][$pos]);
}
if (is_array($dia['prob_precipitacion'][$pos]) && array_key_exists('@attributes', $dia['prob_precipitacion'][$pos])) {
$tiempo['prob_precipitacion'] = $dia['prob_precipitacion'][$pos][0];
} else {
$tiempo['prob_precipitacion'] = $dia['prob_precipitacion'][$pos];
}
$tiempo['fecha'] = $dia['@attributes']['fecha'];
$tiempo['direccion'] = $dia['viento'][$pos]['direccion'];
$tiempo['velocidad'] = $dia['viento'][$pos]['velocidad'];
$tiempo['maxima'] = $dia['temperatura']['maxima'];
$tiempo['minima'] = $dia['temperatura']['minima'];
//Como ya tenemos datos, rompemos el bucle
break;
}
}
}
}
}
return $tiempo;
}
private function obtainBestResults(array $competitionData): ?array
{
$competitionId = $competitionData['id'];
$calculation = $competitionData['calculationId'];
$formula = $competitionData['formula'];
$totalPlayersByTeam = $competitionData['jugadores'];
$round = null;
$competition = $this->em->getRepository(Competicion::class)->find($competitionId);
$compatibleRounds = $competition->getJornadasCompatibles(false);
if (!$compatibleRounds) {
/* @var Jornada $round */
$round = $competition->getJornadas()->first();
}
$bestResult = null;
$formulaId = $competition->getFormula()->getId();
if (empty($round)) {
switch ($totalPlayersByTeam) {
case 1:
if (in_array($formulaId, [MATCH_PLAY, RYDER_CUP], true)) {
$winner = $this->em->getRepository(Encuentro::class)->findWinnerOfIndividualTournament($competitionId);
$results = $winner ? [$winner] : [];
} else {
$results = $this->em->getRepository(Resultado::class)
->bestResultIndividual($competitionId, $calculation);
}
$bestResult = $this->formatBestResult($results);
break;
case 2:
if (in_array($formulaId, [MATCH_PLAY, RYDER_CUP], true)) {
$winner = $this->em->getRepository(Encuentro::class)->findWinnerOfCoupleTournament($competitionId);
$results = $winner ? [$winner] : [];
} else {
$results = $this->em->getRepository(Resultado::class)->bestResultCouple($competitionId, $calculation);
}
$bestResult = $this->formatBestResult($results);
break;
default:
// PARA EQUIPO SE HA DECIDIDO NO HACERLO PORQUE SE SUELEN HACER CLASIFICACIONES DE LAS MEJORES X TARJETAS, Y ES ALGO QUE NO PODEMOS CONTROLAR
break;
}
} else {
$bestResult = $this->obtainBestResultsByRoundFormat($competitionId, $totalPlayersByTeam, $calculation, $round);
}
if (!empty($bestResult)) {
$bestResult['formula'] = $formula;
}
return $bestResult;
}
private function addGroupings(Cliente $client): array
{
$clientId = $client->getId();
$futureGroupings = $this->em->getRepository(Agrupacion::class)->obtainFuturesGroupingByClient($clientId);
$futureGroupings = $this->formatGroupingData($client, $futureGroupings);
$pastGroupings = $this->em->getRepository(Agrupacion::class)->obtainPastGroupingByClient($clientId);
$pastGroupings = $this->formatGroupingData($client, $pastGroupings, false);
return [$futureGroupings, $pastGroupings];
}
private function formatCompetitionData(array $competitions): array
{
$response = [];
foreach ($competitions as $key => $competition) {
$response[$key] = $competition;
$response[$key]['grouping'] = false;
}
return $response;
}
private function formatGroupingData(Cliente $client, array $groupings, bool $isFuture = true): array
{
$organizer = $client->getNombreCorto();
$response = [];
/* @var Agrupacion $grouping */
foreach ($groupings as $key => $grouping) {
$response[$key] = $grouping;
$response[$key]['grouping'] = true;
$response[$key]['fecha'] = min($grouping['fecha_fin'], (new \DateTime('now'))->format('Y-m-d'));
$response[$key]['organizer'] = $organizer;
$response[$key]['club'] = $organizer;
$response[$key]['wagr'] = false;
if ($isFuture) {
$response[$key]['mode'] = 3;
$response[$key]['estado'] = EnumEstadoCompeticion::ABIERTA;
}
}
return $response;
}
private function formatBestResult(array $results): ?array
{
$resultRow = reset($results);
if (!$resultRow) {
return null;
}
return [
'result' => $resultRow['contrapar'],
'player' => $resultRow['player']
];
}
private function obtainBestResultsByRoundFormat(mixed $competitionId, $totalPlayersByTeam, mixed $calculation, Jornada $round): ?array
{
$format = $round->getModalidad()->getId();
if ($totalPlayersByTeam > 2 || PROAM === $format) {
return null;
}
$roundId = $round->getId();
if (INDIVIDUAL === $format) {
$results = $this->em->getRepository(Resultado::class)->bestResultIndividual($competitionId, $calculation, $roundId);
} else {
$results = $this->em->getRepository(Resultado::class)->bestResultCouple($competitionId, $calculation);
}
return $this->formatBestResult($results);
}
private function sortCompetitions(array $competitions, bool $desc = false): array
{
usort($competitions, function ($a, $b) use ($desc) {
$dateA = new DateTime($a['fecha']);
$dateB = new DateTime($b['fecha']);
if ($desc) {
return $dateB <=> $dateA;
} else {
return $dateA <=> $dateB;
}
});
return $competitions;
}
}