<?php
/**
 * POST /modules/turnero/api/ocupar_lugar.php
 *
 * Gestiona la ocupación exclusiva de un puesto (recepción o muestras).
 * Un puesto solo puede tener UN usuario activo.
 *
 * Actions:
 *   claim           → reclamar el puesto (o renovar si ya es mío)
 *   ping            → renovar heartbeat (cada 60 s)
 *   release         → liberar el puesto
 *   solicitar       → usuario B pide transferencia al ocupante A
 *   check_solicitud → A consulta si hay una solicitud pendiente
 *   denegar         → A rechaza la solicitud
 *   aceptar         → A acepta y libera el puesto
 *   check_transfer  → B consulta si el puesto quedó libre o fue denegado
 *   disponibles     → lista puestos del mismo tipo sin ocupante activo
 */

require_once __DIR__ . '/_helpers.php';
requireMethod('POST');

$datos   = inputJson();
$lugarId = (int)($datos['lugar_id'] ?? 0);
$action  = $datos['action'] ?? 'claim';

if ($lugarId <= 0) jsonError('lugar_id inválido.');

$validActions = ['claim','ping','release','solicitar','check_solicitud','denegar','aceptar','check_transfer','disponibles'];
if (!in_array($action, $validActions, true)) jsonError('action inválida.');

$pdo    = db();
$userId = (int)adminId();
$nombre = $_SESSION['admin_user']['full_name']
       ?? $_SESSION['admin_user']['username']
       ?? 'Usuario';

$timeout = 'NOW() - INTERVAL 2 MINUTE';

/* ── release ─────────────────────────────────────────────────── */
if ($action === 'release') {
    $pdo->prepare(
        "DELETE FROM turnero_lugar_ocupacion WHERE lugar_id = ? AND user_id = ?"
    )->execute([$lugarId, $userId]);
    jsonOk(['liberado' => true]);
}

/* ── ping ────────────────────────────────────────────────────── */
if ($action === 'ping') {
    $pdo->prepare(
        "UPDATE turnero_lugar_ocupacion SET ultimo_ping = NOW()
          WHERE lugar_id = ? AND user_id = ?"
    )->execute([$lugarId, $userId]);
    jsonOk(['ok' => true]);
}

/* ── aceptar (ocupante A acepta la solicitud y libera) ───────── */
if ($action === 'aceptar') {
    $pdo->prepare(
        "DELETE FROM turnero_lugar_ocupacion WHERE lugar_id = ? AND user_id = ?"
    )->execute([$lugarId, $userId]);
    jsonOk(['liberado' => true]);
}

/* ── denegar (ocupante A rechaza) ────────────────────────────── */
if ($action === 'denegar') {
    $pdo->prepare(
        "UPDATE turnero_lugar_ocupacion
            SET solicitud_resultado = 'denegada'
          WHERE lugar_id = ? AND user_id = ?"
    )->execute([$lugarId, $userId]);
    jsonOk(['ok' => true]);
}

/* ── check_solicitud (A consulta si hay solicitud pendiente) ─── */
if ($action === 'check_solicitud') {
    $st = $pdo->prepare(
        "SELECT solicitud_user_id, solicitud_nombre, solicitud_at, solicitud_resultado
           FROM turnero_lugar_ocupacion
          WHERE lugar_id = ? AND user_id = ?"
    );
    $st->execute([$lugarId, $userId]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row || $row['solicitud_resultado'] !== 'pendiente') {
        jsonOk(['hay_solicitud' => false]);
    }
    jsonOk([
        'hay_solicitud' => true,
        'solicitante'   => $row['solicitud_nombre'],
        'solicitud_at'  => $row['solicitud_at'],
    ]);
}

/* ── check_transfer (B consulta si el puesto quedó libre) ───── */
if ($action === 'check_transfer') {
    $st = $pdo->prepare(
        "SELECT user_id, solicitud_user_id, solicitud_resultado
           FROM turnero_lugar_ocupacion WHERE lugar_id = ?"
    );
    $st->execute([$lugarId]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) {
        jsonOk(['disponible' => true]);
    }
    if ($row['solicitud_resultado'] === 'denegada') {
        jsonOk(['disponible' => false, 'denegado' => true]);
    }
    jsonOk(['disponible' => false, 'denegado' => false]);
}

/* ── solicitar (B pide transferencia) ───────────────────────── */
if ($action === 'solicitar') {
    // Limpiar expirados primero
    $pdo->prepare(
        "DELETE FROM turnero_lugar_ocupacion WHERE ultimo_ping < $timeout"
    )->execute();

    $st = $pdo->prepare(
        "SELECT user_id, user_nombre, solicitud_at, solicitud_user_id
           FROM turnero_lugar_ocupacion WHERE lugar_id = ?"
    );
    $st->execute([$lugarId]);
    $ocupado = $st->fetch(PDO::FETCH_ASSOC);

    if (!$ocupado || (int)$ocupado['user_id'] === $userId) {
        // Ya libre o soy yo — reclamar directamente
        $pdo->prepare(
            "INSERT INTO turnero_lugar_ocupacion (lugar_id, user_id, user_nombre, ultimo_ping)
             VALUES (?, ?, ?, NOW())
             ON DUPLICATE KEY UPDATE user_id=?, user_nombre=?, ultimo_ping=NOW(),
                 solicitud_user_id=NULL, solicitud_nombre=NULL, solicitud_at=NULL, solicitud_resultado=NULL"
        )->execute([$lugarId, $userId, $nombre, $userId, $nombre]);
        jsonOk(['transferido' => true]);
    }

    // Guardar solicitud (o renovarla si ya existía de este mismo B)
    $pdo->prepare(
        "UPDATE turnero_lugar_ocupacion
            SET solicitud_user_id   = ?,
                solicitud_nombre    = ?,
                solicitud_at        = NOW(),
                solicitud_resultado = 'pendiente'
          WHERE lugar_id = ?"
    )->execute([$userId, $nombre, $lugarId]);

    jsonOk(['solicitado' => true, 'ocupado_por' => $ocupado['user_nombre']]);
}

/* ── disponibles (puestos del mismo tipo sin ocupante) ───────── */
if ($action === 'disponibles') {
    $stLugar = $pdo->prepare("SELECT tipo FROM turnero_lugares WHERE id = ?");
    $stLugar->execute([$lugarId]);
    $lugar = $stLugar->fetch(PDO::FETCH_ASSOC);
    if (!$lugar) jsonError('Lugar no encontrado.', 404);

    $stDisp = $pdo->prepare(
        "SELECT l.id, l.nombre
           FROM turnero_lugares l
          WHERE l.tipo = ? AND l.activo = 1 AND l.id != ?
            AND NOT EXISTS (
                SELECT 1 FROM turnero_lugar_ocupacion o
                 WHERE o.lugar_id = l.id
                   AND o.ultimo_ping >= $timeout
            )
          ORDER BY l.sort_order ASC"
    );
    $stDisp->execute([$lugar['tipo'], $lugarId]);
    jsonOk(['disponibles' => $stDisp->fetchAll(PDO::FETCH_ASSOC)]);
}

/* ── claim ───────────────────────────────────────────────────── */
// Limpiar ocupaciones expiradas
$pdo->prepare(
    "DELETE FROM turnero_lugar_ocupacion WHERE ultimo_ping < $timeout"
)->execute();

// Verificar si hay un ocupante
$st = $pdo->prepare(
    "SELECT user_id, user_nombre, solicitud_user_id, solicitud_at, solicitud_resultado
       FROM turnero_lugar_ocupacion WHERE lugar_id = ?"
);
$st->execute([$lugarId]);
$ocupado = $st->fetch(PDO::FETCH_ASSOC);

if ($ocupado && (int)$ocupado['user_id'] !== $userId) {
    // Si hay una solicitud de este usuario pendiente hace más de 6s → auto-liberar
    $esMiSolicitud  = (int)($ocupado['solicitud_user_id'] ?? 0) === $userId;
    $solicitudVieja = $ocupado['solicitud_at'] && (strtotime($ocupado['solicitud_at']) < time() - 6);
    if ($esMiSolicitud && $solicitudVieja) {
        $pdo->prepare("DELETE FROM turnero_lugar_ocupacion WHERE lugar_id = ?")
            ->execute([$lugarId]);
        $ocupado = null; // caer al INSERT/UPDATE de abajo
    } else {
        jsonOk([
            'disponible'  => false,
            'ocupado_por' => $ocupado['user_nombre'],
        ]);
    }
}

// Reclamar o renovar
$pdo->prepare(
    "INSERT INTO turnero_lugar_ocupacion (lugar_id, user_id, user_nombre, ultimo_ping)
     VALUES (?, ?, ?, NOW())
     ON DUPLICATE KEY UPDATE user_id=?, user_nombre=?, ultimo_ping=NOW(),
         solicitud_user_id=NULL, solicitud_nombre=NULL, solicitud_at=NULL, solicitud_resultado=NULL"
)->execute([$lugarId, $userId, $nombre, $userId, $nombre]);

jsonOk(['disponible' => true]);
