false, 'message' => 'Método no permitido. Use POST']); exit(); } try { $input = json_decode(file_get_contents('php://input'), true); if (!$input) $input = $_POST; if (!isset($input['id']) || !isset($input['motivo'])) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Faltan datos obligatorios (id y motivo)']); exit(); } $id = (int)$input['id']; $motivo = trim($input['motivo']); if (empty($motivo)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'El motivo no puede estar vacío']); exit(); } // 1) Obtener la reserva actual $stmt = $pdo->prepare(" SELECT r.id, r.codigo, r.estado, r.cabina_id, r.importe, r.referencia_bizum, r.usuario_id, r.fecha, r.hora_inicio, r.hora_fin_prevista, u.nombre AS cliente_nombre, u.apellidos AS cliente_apellidos, u.email AS cliente_email, u.telefono AS cliente_telefono, m.nombre AS mascota_nombre, m.especie AS mascota_especie, c.codigo AS cabina_codigo, c.bloque FROM reservas r JOIN usuarios u ON r.usuario_id = u.id JOIN mascotas m ON r.mascota_id = m.id JOIN cabinas c ON r.cabina_id = c.id WHERE r.id = ? "); $stmt->execute([$id]); $reserva = $stmt->fetch(); if (!$reserva) { http_response_code(404); echo json_encode(['success' => false, 'message' => 'Reserva no encontrada']); exit(); } // 2) Validar estado $estados_cancelables = ['pendiente_pago', 'pagada_pendiente_aprobacion', 'confirmada', 'activa']; if (!in_array($reserva['estado'], $estados_cancelables)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'No se puede cancelar una reserva en estado: ' . $reserva['estado']]); exit(); } // 3) Iniciar transacción $pdo->beginTransaction(); // 4) Cancelar la reserva y registrar motivo $stmt = $pdo->prepare(" UPDATE reservas SET estado = 'cancelada', hora_salida_real = NOW(), motivo_cancelacion = ? WHERE id = ? "); $stmt->execute([$motivo, $id]); // 5) Liberar la cabina $stmtCabina = $pdo->prepare(" UPDATE cabinas SET estado = 'disponible' WHERE id = ? AND estado IN ('ocupada', 'reservada') "); $stmtCabina->execute([$reserva['cabina_id']]); // 6) Desactivar QR $stmtQR = $pdo->prepare("UPDATE reservas SET qr_activo = 0, codigo_qr = NULL WHERE id = ?"); $stmtQR->execute([$id]); // 7) ✅ ENVIAR EMAIL AL CLIENTE (si tiene email) $email_enviado = false; $email_error = null; if (!empty($reserva['cliente_email'])) { $nombreCliente = trim($reserva['cliente_nombre'] . ' ' . $reserva['cliente_apellidos']); $fechaFormateada = date('d/m/Y', strtotime($reserva['fecha'])); $horaInicio = substr($reserva['hora_inicio'], 0, 5); $importe = number_format($reserva['importe'], 2, ',', '.') . ' €'; $asunto = "❌ PetStop - Reserva cancelada: " . $reserva['codigo']; $cuerpo = "

Notificación de cancelación

Hola {$nombreCliente},

Lamentamos informarte que tu reserva ha sido cancelada.

📋 Código reserva: {$reserva['codigo']}
📅 Fecha: {$fechaFormateada}
🕐 Hora: {$horaInicio}
🏠 Cabina: {$reserva['cabina_codigo']} (Bloque {$reserva['bloque']})
🐾 Mascota: {$reserva['mascota_nombre']} ({$reserva['mascota_especie']})
💶 Importe: {$importe}
Motivo de la cancelación:

{$motivo}

Si tienes cualquier duda, contáctanos respondiendo a este email o llamando al teléfono del centro.

Atentamente,
El equipo de PetStop 🐾

"; $resultado = enviarEmailSMTP( $reserva['cliente_email'], $asunto, $cuerpo, $nombreCliente ); if ($resultado['success']) { $email_enviado = true; } else { $email_error = $resultado['error']; error_log('Error enviando email de cancelación: ' . $email_error); } } // 8) Confirmar transacción $pdo->commit(); // 9) Respuesta al frontend $mensaje = 'Reserva cancelada correctamente'; if ($email_enviado) { $mensaje .= ' y email enviado al cliente.'; } elseif (!empty($reserva['cliente_email'])) { $mensaje .= ', pero no se pudo enviar el email (revisa el log).'; } else { $mensaje .= '. El cliente no tiene email, no se envió notificación.'; } echo json_encode([ 'success' => true, 'message' => $mensaje, 'email_enviado' => $email_enviado, 'data' => [ 'id' => $id, 'codigo' => $reserva['codigo'], 'estado_anterior' => $reserva['estado'], 'estado_nuevo' => 'cancelada', 'motivo' => $motivo, 'cabina_liberada' => $reserva['cabina_id'] ] ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); } catch (PDOException $e) { if ($pdo->inTransaction()) $pdo->rollBack(); http_response_code(500); echo json_encode(['success' => false, 'message' => 'Error en el servidor', 'error' => $e->getMessage()]); } ?>