<?php
// ============================================
// SEN RDV SANTÉ+ — Plages ouvertes
// GET    /api/rdv/plages.php              → liste plages actives
// GET    /api/rdv/plages.php?service_id=X → filtrer par service
// POST   /api/rdv/plages.php              → ouvrir une plage (période + durée)
// PUT    /api/rdv/plages.php              → modifier le quota d'une plage existante
// DELETE /api/rdv/plages.php              → fermer une plage
// Headers: Authorization: Bearer {token gérant}
//
// En mode quota    : duree_minutes non requis, quota obligatoire
// En mode creneaux : duree_minutes obligatoire, quota ignoré
// Le mode est choisi par le gérant dans le body (mode_rdv),
// indépendamment du mode par défaut du service en DB
// ============================================

require_once '../config/helpers.php';
require_once '../config/database.php';

if (!in_array($_SERVER['REQUEST_METHOD'], ['GET', 'POST', 'PUT', 'DELETE'])) {
    repondre(['erreur' => 'Méthode non autorisée'], 405);
}

$userConnecte = verifierToken();
if (!in_array($userConnecte['role'], ['gerant', 'admin_hopital'])) {
    repondre(['erreur' => 'Accès non autorisé'], 403);
}

$db         = getDB();
$method     = $_SERVER['REQUEST_METHOD'];
$isGerant   = $userConnecte['role'] === 'gerant';
$serviceIds = $userConnecte['service_ids'] ?? [];

if ($isGerant && empty($serviceIds)) {
    repondre(['erreur' => 'Aucun service rattaché à votre compte'], 400);
}

function assertServiceAutorise($serviceId, $serviceIds, $isGerant) {
    if ($isGerant && !in_array((int)$serviceId, $serviceIds)) {
        repondre(['erreur' => 'Ce service ne vous appartient pas'], 403);
    }
}

// ── helper : envoyer alertes push + SMS aux patients en attente ──
function envoyerAlertes($db, $serviceId, $dateDebut, $dateFin, $heureDebut, $heureFin) {
    $alertes = $db->prepare("
        SELECT a.patient_id, u.push_token, u.telephone
        FROM alertes_disponibilite a
        JOIN utilisateurs u ON u.id = a.patient_id
        WHERE a.service_id = ? AND a.actif = 1
        ORDER BY a.created_at ASC
    ");
    $alertes->execute([$serviceId]);
    $patients = $alertes->fetchAll(PDO::FETCH_ASSOC);
    if (empty($patients)) return;

    $stmtSrv = $db->prepare("
        SELECT s.nom AS service_nom, h.id AS hopital_id, h.nom AS hopital_nom
        FROM services s
        JOIN hopitaux h ON h.id = s.hopital_id
        WHERE s.id = ?
    ");
    $stmtSrv->execute([$serviceId]);
    $srv = $stmtSrv->fetch(PDO::FETCH_ASSOC);

    $periode = ($dateDebut === $dateFin)
        ? "le {$dateDebut}"
        : "du {$dateDebut} au {$dateFin}";

    $msgSms = "SEN RDV SANTÉ+ : Créneaux disponibles {$periode} de {$heureDebut} à {$heureFin} ({$srv['service_nom']} - {$srv['hopital_nom']}). Réservez vite !";
    $expoPushTokens = [];

    foreach ($patients as $patient) {
        $db->prepare("
            INSERT INTO notifications (utilisateur_id, type, canal, message)
            VALUES (?, 'flash', 'sms', ?)
        ")->execute([$patient['patient_id'], $msgSms]);

        if (!empty($patient['push_token'])) {
            $expoPushTokens[] = [
                'to'    => $patient['push_token'],
                'title' => '🏥 Créneaux disponibles !',
                'body'  => "{$periode} de {$heureDebut} à {$heureFin} — {$srv['service_nom']} ({$srv['hopital_nom']})",
                'data'  => [
                    'type'       => 'flash',
                    'service_id' => (int)$serviceId,
                    'hopital_id' => (int)$srv['hopital_id'],
                ],
                'sound'     => 'default',
                'priority'  => 'high',
                'channelId' => 'senrdv',
            ];
        }
    }

    if (!empty($expoPushTokens)) {
        $ch = curl_init('https://exp.host/--/api/v2/push/send');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Accept: application/json'],
            CURLOPT_POSTFIELDS     => json_encode($expoPushTokens),
            CURLOPT_TIMEOUT        => 15,
        ]);
        $reponse = curl_exec($ch);
        $erreur  = curl_error($ch);
        curl_close($ch);
        if ($erreur) error_log("Expo push erreur cURL: $erreur");
        else         error_log("Expo push réponse: $reponse");
    }

    $db->prepare("UPDATE alertes_disponibilite SET actif = 0 WHERE service_id = ? AND actif = 1")
       ->execute([$serviceId]);
}

// ════════════════════════════════════
// GET — liste des plages actives
// ════════════════════════════════════
if ($method === 'GET') {
    if (!empty($_GET['service_id'])) {
        assertServiceAutorise($_GET['service_id'], $serviceIds, $isGerant);
        $filtreSql    = "AND p.service_id = ?";
        $filtreParams = [(int)$_GET['service_id']];
    } elseif ($isGerant) {
        $placeholders = implode(',', array_fill(0, count($serviceIds), '?'));
        $filtreSql    = "AND p.service_id IN ($placeholders)";
        $filtreParams = $serviceIds;
    } else {
        $filtreSql    = "AND s.hopital_id = ?";
        $filtreParams = [$userConnecte['hopital_id']];
    }

    $stmt = $db->prepare("
        SELECT p.*, s.nom AS service_nom, s.mode_rdv,
               u.prenom AS gerant_prenom, u.nom AS gerant_nom
        FROM plages_ouvertes p
        JOIN services s ON s.id = p.service_id
        JOIN utilisateurs u ON u.id = p.created_by
        WHERE p.actif = 1
          AND p.date_plage >= CURDATE()
          $filtreSql
        ORDER BY p.date_plage ASC, p.heure_debut ASC
    ");
    $stmt->execute($filtreParams);

    repondre([
        'succes'   => true,
        'services' => $userConnecte['services'] ?? [],
        'plages'   => $stmt->fetchAll(PDO::FETCH_ASSOC),
    ]);
}

// ════════════════════════════════════
// POST — ouvrir une plage
// ════════════════════════════════════
if ($method === 'POST') {
    $body = getBody();
    validerChamps($body, ['service_id', 'date_debut', 'date_fin', 'heure_debut', 'heure_fin']);

    $serviceId  = (int)$body['service_id'];
    $dateDebut  = $body['date_debut'];
    $dateFin    = $body['date_fin'];
    $heureDebut = $body['heure_debut'];
    $heureFin   = $body['heure_fin'];

    assertServiceAutorise($serviceId, $serviceIds, $isGerant);

    // je récupère le service (pour quota_journalier par défaut)
    $stmtSvc = $db->prepare("SELECT mode_rdv, quota_journalier FROM services WHERE id = ?");
    $stmtSvc->execute([$serviceId]);
    $service = $stmtSvc->fetch(PDO::FETCH_ASSOC);
    if (!$service) repondre(['erreur' => 'Service introuvable'], 404);

    // ✅ le mode vient du choix du gérant dans le body
    // si non fourni, fallback sur le mode du service en DB
    $modeRdv = (isset($body['mode_rdv']) && in_array($body['mode_rdv'], ['creneaux', 'quota']))
        ? $body['mode_rdv']
        : ($service['mode_rdv'] ?? 'creneaux');

    // ── validation selon le mode choisi ──
    if ($modeRdv === 'creneaux') {
        if (empty($body['duree_minutes'])) {
            repondre(['erreur' => 'duree_minutes obligatoire en mode créneaux'], 422);
        }
        $dureeMinutes = (int)$body['duree_minutes'];
        if (!in_array($dureeMinutes, [10, 15, 20, 30, 45, 60])) {
            repondre(['erreur' => 'Durée invalide (10, 15, 20, 30, 45 ou 60 minutes)'], 422);
        }
        $quota = null;
    } else {
        // mode quota : le gérant peut surcharger le quota du service pour cette plage
        $dureeMinutes = null;
        $quota = isset($body['quota']) && (int)$body['quota'] > 0
            ? (int)$body['quota']
            : ($service['quota_journalier'] ?? 10);
    }

    if ($dateDebut > $dateFin) {
        repondre(['erreur' => 'La date de début doit être avant la date de fin'], 422);
    }
    if ($heureDebut >= $heureFin) {
        repondre(['erreur' => "L'heure de début doit être avant l'heure de fin"], 422);
    }

    $dates   = [];
    $current = new DateTime($dateDebut);
    $end     = new DateTime($dateFin);
    while ($current <= $end) {
        $dates[] = $current->format('Y-m-d');
        $current->modify('+1 day');
    }

    $prixReservation = (float) getParametre('prix_reservation', 200);
    $expireAt        = date('Y-m-d H:i:s', strtotime('+3 hours'));
    $plagesCreees    = 0;
    $rdvsConfirmes   = 0;
    $doublons        = 0;

    foreach ($dates as $datePlage) {

        // doublon check
        $stmtCheck = $db->prepare("
            SELECT COUNT(*) AS total FROM plages_ouvertes
            WHERE service_id = ? AND date_plage = ? AND actif = 1
            AND (
                (heure_debut <= ? AND heure_fin >= ?) OR
                (heure_debut <= ? AND heure_fin >= ?) OR
                (heure_debut >= ? AND heure_fin <= ?)
            )
        ");
        $stmtCheck->execute([
            $serviceId, $datePlage,
            $heureDebut, $heureDebut,
            $heureFin,   $heureFin,
            $heureDebut, $heureFin,
        ]);
        if ($stmtCheck->fetch(PDO::FETCH_ASSOC)['total'] > 0) {
            $doublons++;
            continue;
        }

        // j'insère la plage
        $stmtInsert = $db->prepare("
            INSERT INTO plages_ouvertes
                (service_id, date_plage, heure_debut, heure_fin,
                 duree_creneau, quota, mode_rdv, created_by)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ");
        $stmtInsert->execute([
            $serviceId, $datePlage, $heureDebut, $heureFin,
            $dureeMinutes, $quota, $modeRdv,
            $userConnecte['utilisateur_id'],
        ]);
        $plagesCreees++;

        if ($modeRdv === 'creneaux') {
            // mode créneaux : je génère les créneaux horaires
            $heureActuelle = new DateTime($datePlage . ' ' . $heureDebut);
            $heureLimite   = new DateTime($datePlage . ' ' . $heureFin);

            while ($heureActuelle < $heureLimite) {
                $heureCreneauDebut = $heureActuelle->format('H:i:s');
                $heureActuelle->modify("+{$dureeMinutes} minutes");
                $heureCreneauFin   = $heureActuelle->format('H:i:s');
                if ($heureActuelle > $heureLimite) break;

                $db->prepare("
                    INSERT INTO creneaux
                        (service_id, jour_semaine, heure_debut, heure_fin, disponible, date_specifique)
                    VALUES (?, ?, ?, ?, 1, ?)
                    ON DUPLICATE KEY UPDATE disponible = 1
                ")->execute([
                    $serviceId,
                    (int)(new DateTime($datePlage))->format('N'),
                    $heureCreneauDebut,
                    $heureCreneauFin,
                    $datePlage,
                ]);
            }
        }
        // mode quota : pas de créneaux générés — numéros de file attribués à la création du RDV

        // confirmation auto des RDVs en_attente dans cette plage
        $stmt2 = $db->prepare("
            SELECT r.id, r.patient_id, u.telephone AS patient_telephone,
                   r.heure_rdv, s.nom AS service_nom
            FROM rendez_vous r
            JOIN services s ON s.id = r.service_id
            JOIN utilisateurs u ON u.id = r.patient_id
            WHERE r.service_id = ?
              AND r.date_rdv = ?
              AND r.heure_rdv >= ?
              AND r.heure_rdv <= ?
              AND r.statut = 'en_attente'
        ");
        $stmt2->execute([
            $serviceId, $datePlage,
            $heureDebut . ':00',
            $heureFin   . ':00',
        ]);
        $rdvsExistants = $stmt2->fetchAll(PDO::FETCH_ASSOC);

        foreach ($rdvsExistants as $rdv) {
            $db->prepare("UPDATE rendez_vous SET statut = 'confirme' WHERE id = ?")
               ->execute([$rdv['id']]);

            $db->prepare("
                INSERT INTO paiements (rdv_id, montant, operateur, telephone_paiement, expire_at)
                VALUES (?, ?, 'wave', ?, ?)
            ")->execute([$rdv['id'], $prixReservation, $rdv['patient_telephone'], $expireAt]);

            $heure = substr($rdv['heure_rdv'], 0, 5);
            $msg   = "SEN RDV SANTÉ+ : Votre RDV du {$datePlage} à {$heure} ({$rdv['service_nom']}) est confirmé. Payez via Mobile Money. Expire dans 3h.";
            $db->prepare("
                INSERT INTO notifications (utilisateur_id, rdv_id, type, canal, message)
                VALUES (?, ?, 'confirmation', 'sms', ?)
            ")->execute([$rdv['patient_id'], $rdv['id'], $msg]);

            $rdvsConfirmes++;
        }
    }

    envoyerAlertes($db, $serviceId, $dateDebut, $dateFin, $heureDebut, $heureFin);

    $msg = "✅ {$plagesCreees} plage(s) ouverte(s)";
    if ($doublons > 0)      $msg .= " ({$doublons} jour(s) ignoré(s) car déjà planifié(s))";
    if ($rdvsConfirmes > 0) $msg .= " — {$rdvsConfirmes} RDV confirmé(s) automatiquement";
    if ($modeRdv === 'quota') $msg .= " · Quota : {$quota} patients/jour";

    repondre([
        'succes'         => true,
        'message'        => $msg,
        'mode_rdv'       => $modeRdv,
        'quota'          => $quota,
        'plages_creees'  => $plagesCreees,
        'doublons'       => $doublons,
        'rdvs_confirmes' => $rdvsConfirmes,
        'date_debut'     => $dateDebut,
        'date_fin'       => $dateFin,
        'heure_debut'    => $heureDebut,
        'heure_fin'      => $heureFin,
        'duree_minutes'  => $dureeMinutes,
    ]);
}

// ════════════════════════════════════
// PUT — modifier le quota d'une plage existante
// ════════════════════════════════════
if ($method === 'PUT') {
    $body = getBody();
    validerChamps($body, ['id', 'quota']);

    $quota = (int)$body['quota'];
    if ($quota <= 0) repondre(['erreur' => 'Le quota doit être supérieur à 0'], 422);

    $stmt = $db->prepare("
        SELECT p.service_id, p.mode_rdv, p.date_plage,
               (SELECT COUNT(*) FROM rendez_vous r
                WHERE r.service_id = p.service_id AND r.date_rdv = p.date_plage
                AND r.statut NOT IN ('annule','expire')) AS rdvs_pris
        FROM plages_ouvertes p
        WHERE p.id = ? AND p.actif = 1
    ");
    $stmt->execute([$body['id']]);
    $plage = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$plage) repondre(['erreur' => 'Plage introuvable'], 404);

    assertServiceAutorise($plage['service_id'], $serviceIds, $isGerant);

    if ($plage['mode_rdv'] !== 'quota') {
        repondre(['erreur' => 'Le quota ne peut être modifié que sur une plage en mode quota'], 422);
    }

    $rdvsPris = (int)$plage['rdvs_pris'];
    if ($quota < $rdvsPris) {
        repondre([
            'erreur' => "Impossible — {$rdvsPris} RDV déjà pris pour ce jour. Le quota minimum est {$rdvsPris}.",
        ], 409);
    }

    $db->prepare("UPDATE plages_ouvertes SET quota = ? WHERE id = ?")
       ->execute([$quota, $body['id']]);

    $db->prepare("UPDATE services SET quota_journalier = ? WHERE id = ?")
       ->execute([$quota, $plage['service_id']]);

    repondre([
        'succes'    => true,
        'message'   => "Quota mis à jour : {$quota} patients/jour",
        'quota'     => $quota,
        'rdvs_pris' => $rdvsPris,
    ]);
}

// ════════════════════════════════════
// DELETE — fermer une plage
// ════════════════════════════════════
if ($method === 'DELETE') {
    $body = getBody();
    if (empty($body['id'])) repondre(['erreur' => 'id obligatoire'], 422);

    $stmt = $db->prepare("SELECT service_id FROM plages_ouvertes WHERE id = ?");
    $stmt->execute([$body['id']]);
    $plage = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$plage) repondre(['erreur' => 'Plage introuvable'], 404);

    assertServiceAutorise($plage['service_id'], $serviceIds, $isGerant);

    $db->prepare("UPDATE plages_ouvertes SET actif = 0 WHERE id = ? AND created_by = ?")
       ->execute([$body['id'], $userConnecte['utilisateur_id']]);

    repondre(['succes' => true, 'message' => 'Plage fermée']);
}