<?php
namespace App\Controller;
use Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use GuzzleHttp\Client;
class PlanityWebSocketController extends AbstractController
{
private $firebaseConfig = [
'apiKey' => "AIzaSyDrSE1PzMwLKyhEvh2x8eV7s1NYwKGRC5Q",
'authDomain' => "planity-production.firebaseapp.com",
'projectId' => "planity-production",
'storageBucket' => "planity-production.appspot.com",
'messagingSenderId' => "1025269755978",
'appId' => "1:1025269755978:web:26e77f72a3cbd599",
'databaseURL' => "https://planity-production-fr-13.europe-west1.firebasedatabase.app"
];
private $client;
private $authToken;
public function __construct()
{
$this->client = new Client();
}
/**
* Initialise la connexion Firebase et récupère le token d'authentification
*/
private function initialize(): void
{
// Vérifier si le token d'authentification existe déjà
if ($this->authToken !== null) {
// Déjà authentifié, ne rien faire
return;
}
try {
$response = $this->client->post(
'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword',
[
'json' => [
'email' => $_ENV['FIREBASE_EMAIL'] ?? 'contact@immybeauty.fr',
'password' => $_ENV['FIREBASE_PASSWORD'] ?? 'Adamjamel93',
'returnSecureToken' => true
],
'query' => [
'key' => $this->firebaseConfig['apiKey']
]
]
);
$data = json_decode((string) $response->getBody(), true);
$this->authToken = $data['idToken'];
} catch (\Exception $e) {
throw new \Exception('Erreur d\'authentification Firebase: ' . $e->getMessage());
}
}
/**
* Récupère le planning pour une date donnée
*/
public function getPlanning(string $date = null): JsonResponse
{
try {
$this->initialize();
$date = $date ?? date('Y-m-d');
$planningData = $this->fetchPlanningData($date);
$validAppointments = $this->filterValidAppointments($planningData);
$formattedAppointments = $this->formatAppointments($validAppointments);
return new JsonResponse([
'date' => $date,
'appointments' => $formattedAppointments
]);
} catch (\Exception $e) {
return new JsonResponse([
'error' => 'Erreur lors de la récupération du planning',
'message' => $e->getMessage()
], 500);
}
}
/**
* Récupère les données du planning depuis Firebase
*/
private function fetchPlanningData(string $date): array
{
$queryParams = [
'orderBy' => '"s"',
'startAt' => '"' . $date . ' 00:00:00"',
'endAt' => '"' . $date . ' 23:59:59"',
'auth' => $this->authToken
];
$response = $this->client->get(
$this->firebaseConfig['databaseURL'] . '/calendar_vevents/-NpLfj6VkVASdkJk886Q.json',
['query' => $queryParams]
);
return json_decode((string) $response->getBody(), true) ?? [];
}
/**
* Filtre les rendez-vous valides (non supprimés)
*/
private function filterValidAppointments(array $planningData): array
{
$validAppointments = [];
foreach ($planningData as $key => $event) {
if (!isset($event['dat'])) {
$validAppointments[$key] = $event;
}
}
uasort($validAppointments, function($a, $b) {
return strtotime($a['s']) - strtotime($b['s']);
});
return $validAppointments;
}
/**
* Formate les rendez-vous pour l'affichage
*/
private function formatAppointments(array $appointments): array
{
$formattedAppointments = [];
$processedEmails = []; // Pour tracker les emails déjà traités
foreach ($appointments as $key => $event) {
$formattedAppointment = $this->formatAppointment($key, $event);
// Si l'appointment est valide (contient un email)
if ($formattedAppointment !== null) {
$clientEmail = $formattedAppointment['appointment']['client']['email'];
// Vérifier si cet email n'a pas déjà été traité
if (!in_array($clientEmail, $processedEmails)) {
$processedEmails[] = $clientEmail;
$formattedAppointments[] = $formattedAppointment;
}
}
}
return $formattedAppointments;
}
/**
* Récupère l'email d'un client via l'API Algolia si nécessaire
*/
private function fetchClientEmail(string $clientId): string
{
try {
$httpClient = new Client();
$response = $httpClient->post(
'https://day79mubw3-dsn.algolia.net/1/indexes/business_customers/query',
[
'headers' => [
'accept' => 'application/json',
'content-type' => 'application/x-www-form-urlencoded',
'x-algolia-agent' => 'Algolia for JavaScript (3.35.1); Browser',
'x-algolia-application-id' => 'DAY79MUBW3',
'x-algolia-api-key' => 'YjE0OWQzYWNkYzNkNThjMDM1MTk1MTMzZmM0NzQ5YzdkYmI0YjAzNDhiZThhM2RhNGEzNjA5NWJhZjdkNjQ1NGZpbHRlcnM9YnVzaW5lc3NJZCUzQS1Oak1aem5iVnBHZmpwR2M2aDho'
],
'body' => json_encode([
'params' => 'filters=id:"' . $clientId . '"&attributesToRetrieve=["email"]'
])
]
);
$result = json_decode((string) $response->getBody(), true);
return $result['hits'][0]['email'] ?? '';
} catch (\Exception $e) {
error_log("Erreur lors de la récupération de l'email pour le client $clientId: " . $e->getMessage());
return '';
}
}
/**
* Récupère l'email du client selon différentes sources
*/
private function getClientEmail(array $event, array $client, string $clientId): string
{
// Priorité 1: Email dans les données de l'événement
if (isset($event['t']) && $event['t'] === 'd' && isset($event['d']['b']['d']['email'])) {
return $event['d']['b']['d']['email'];
}
// Priorité 2: Email dans les données du client
if (isset($client['email'])) {
return $client['email'];
}
// Priorité 3: Recherche via Algolia
if ($clientId !== 'Non renseigné') {
try {
return $this->fetchClientEmail($clientId);
} catch (\Exception $e) {
error_log("Erreur lors de la récupération de l'email pour le client $clientId: " . $e->getMessage());
}
}
return '';
}
/**
* Formate un rendez-vous individuel
*/
private function formatAppointment($key, $event): ?array
{
try {
$timestamp = isset($event['cat']) ? $event['cat'] : time();
// Préparation des données
$dateHeure = isset($event['s']) ? $event['s'] : 'Non renseigné';
$duree = isset($event['d']) ? $event['d'] : '0';
$modifieLe = isset($event['uat']) ? date('d/m/Y H:i:s', $event['uat']) : 'Non modifié';
// Client
// Client
$client = isset($event['cu']) ? $event['cu'] : array();
$clientNom = isset($client['name']) ? $client['name'] : 'Non renseigné';
$clientPhone = isset($client['phone']) ? $client['phone'] : 'Non renseigné';
$clientId = isset($client['id']) ? $client['id'] : 'Non renseigné';
// Tentative de récupération de l'email
$clientEmail = $this->getClientEmail($event, $client, $clientId);
$clientId = isset($client['id']) ? $client['id'] : 'Non renseigné';
$clientSupprime = isset($client['d']) ? 'Oui' : 'Non';
$nouveauClient = isset($event['nc']) && $event['nc'] === true ? 'Oui' : 'Non';
// Prestation
$prestationNom = isset($event['t']) ? $event['t'] : 'Non renseigné';
$prestationPrix = isset($event['seop']) ? $event['seop'] : '0';
$prestationId = isset($event['se']) ? $event['se'] : 'Non renseigné';
$prestationOption = isset($event['seo']) ? $event['seo'] : 'Non renseigné';
$prestationIndex = isset($event['seoi']) ? $event['seoi'] : 'Non renseigné';
// Paiement
$paiementStatut = isset($event['opd']) ? $event['opd'] : 'Non renseigné';
$paiementMontant = isset($event['p']) ? $event['p'] : (isset($event['seop']) ? $event['seop'] : '0');
$paiementTransaction = isset($event['opcid']) ? $event['opcid'] : 'Non renseigné';
$paiementMethode = isset($event['oppm']) ? $event['oppm'] : 'Non renseigné';
$paiementReduction = isset($event['opcr']) ? $event['opcr'] : '0';
$paiementCarte = isset($event['opl4']) ? $event['opl4'] : 'Non renseigné';
// Source
$source = isset($event['cby']) ? $event['cby'] : 'Non renseigné';
$plateforme = isset($event['fo']) ? $event['fo'] : 'web';
$calendrierId = isset($event['ca']) ? $event['ca'] : 'Non renseigné';
$sequence = isset($event['sq']) ? $event['sq'] : 'Non renseigné';
// echo "
// <div style='margin: 20px; padding: 20px; border: 1px solid #ddd; border-radius: 8px; font-family: Arial;'>
// <h2 style='color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px;'>
// 🕒 Rendez-vous #{$key}
// </h2>
//
// <div style='display: grid; grid-template-columns: 1fr 1fr; gap: 20px;'>
// <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
// <h3 style='color: #2980b9;'>⏰ Informations Horaires</h3>
// <ul style='list-style: none; padding: 0;'>
// <li><strong>Date/Heure:</strong> {$dateHeure}</li>
// <li><strong>Durée:</strong> {$duree} minutes</li>
// <li><strong>Créé le:</strong> " . date('d/m/Y H:i:s', $timestamp) . "</li>
// <li><strong>Modifié le:</strong> {$modifieLe}</li>
// </ul>
// </div>
//
// <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
// <h3 style='color: #2980b9;'>👤 Client</h3>
// <ul style='list-style: none; padding: 0;'>
// <li><strong>Nom:</strong> {$clientNom}</li>
// <li><strong>Téléphone:</strong> {$clientPhone}</li>
// <li><strong>Email:</strong> {$clientEmail}</li>
// <li><strong>ID Client:</strong> {$clientId}</li>
// <li><strong>Nouveau client:</strong> {$nouveauClient}</li>
// <li><strong>Supprimé:</strong> {$clientSupprime}</li>
// </ul>
// </div>
//
// <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
// <h3 style='color: #2980b9;'>💇 Prestation</h3>
// <ul style='list-style: none; padding: 0;'>
// <li><strong>Nom:</strong> {$prestationNom}</li>
// <li><strong>Prix:</strong> {$prestationPrix}€</li>
// <li><strong>ID Service:</strong> {$prestationId}</li>
// <li><strong>Option Service:</strong> {$prestationOption}</li>
// <li><strong>Index Option:</strong> {$prestationIndex}</li>
// </ul>
// </div>
//
// <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
// <h3 style='color: #2980b9;'>💳 Paiement</h3>
// <ul style='list-style: none; padding: 0;'>
// <li><strong>Statut:</strong> {$paiementStatut}</li>
// <li><strong>Montant:</strong> {$paiementMontant}€</li>
// <li><strong>ID Transaction:</strong> {$paiementTransaction}</li>
// <li><strong>Méthode:</strong> {$paiementMethode}</li>
// <li><strong>Réduction:</strong> {$paiementReduction}%</li>
// <li><strong>Derniers chiffres carte:</strong> {$paiementCarte}</li>
// </ul>
// </div>
//
// <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
// <h3 style='color: #2980b9;'>📝 Métadonnées</h3>
// <ul style='list-style: none; padding: 0;'>
// <li><strong>Source:</strong> {$source}</li>
// <li><strong>Plateforme:</strong> {$plateforme}</li>
// <li><strong>ID Calendrier:</strong> {$calendrierId}</li>
// <li><strong>Séquence:</strong> {$sequence}</li>
// </ul>
// </div>
//
// <div style='background: #f8f9fa; padding: 15px; border-radius: 5px;'>
// <h3 style='color: #2980b9;'>🔍 Données Brutes</h3>
// <pre style='background: #eee; padding: 10px; overflow: auto; max-height: 200px;'>" .
// json_encode($event, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) .
// "</pre>
// </div>
// </div>
// </div>";
if (!empty($clientEmail)) {
return [
'appointment' => [
'date' => $dateHeure,
'client' => [
'name' => $clientNom,
'email' => $clientEmail
]
]
];
}
// Si pas d'email, retourner null ou un tableau vide
return null; // ou return [];
} catch (Exception $e) {
error_log("Erreur de formatage pour le rendez-vous $key: " . json_encode($event));
throw $e;
}
}
#[Route('/admin/search-clients-planity', name: 'search_clients', methods: ['GET'])]
public function searchClientsFromPlanity(Request $request): JsonResponse
{
try {
$searchTerm = $request->query->get('q');
$client = new Client();
$response = $client->post(
'https://day79mubw3-dsn.algolia.net/1/indexes/business_customers/query',
[
'headers' => [
'accept' => 'application/json',
'content-type' => 'application/x-www-form-urlencoded',
'x-algolia-agent' => 'Algolia for JavaScript (3.35.1); Browser',
'x-algolia-application-id' => 'DAY79MUBW3',
'x-algolia-api-key' => 'YjE0OWQzYWNkYzNkNThjMDM1MTk1MTMzZmM0NzQ5YzdkYmI0YjAzNDhiZThhM2RhNGEzNjA5NWJhZjdkNjQ1NGZpbHRlcnM9YnVzaW5lc3NJZCUzQS1Oak1aem5iVnBHZmpwR2M2aDho'
],
'body' => json_encode([
'params' => "query={$searchTerm}&hitsPerPage=5"
])
]
);
$data = json_decode((string) $response->getBody(), true);
return new JsonResponse($data);
} catch (\Exception $e) {
return new JsonResponse(['error' => $e->getMessage()], 500);
}
}
}