const express = require('express'); const router = express.Router(); const Hotspot = require('../models/Hotspot'); const Scene = require('../models/Scene'); const { protect } = require('../middlewares/authMiddleware'); const { calculateReverseYaw } = require('../utils/hotspotHelper'); /** * @route GET /api/hotspots/:scene_id * @desc Lấy toàn bộ danh sách hotspot của một cảnh */ router.get('/:scene_id', async (req, res) => { try { const hotspots = await Hotspot.find({ parent_scene_id: req.params.scene_id }) .populate({ path: 'target_scene_id', select: 'name title assetId privacy shareToken', populate: { path: 'assetId', select: '_id' } }) .lean(); res.json(hotspots); } catch (error) { res.status(500).json({ message: error.message }); } }); /** * @route POST /api/hotspots/create * @desc Tạo mới Hotspot và tự động tạo liên kết quay lại */ router.post('/create', protect, async (req, res) => { try { const { parent_scene_id, target_scene_id, title, description, coordinates } = req.body; const parentScene = await Scene.findById(parent_scene_id); if (!parentScene || parentScene.createdBy.toString() !== req.user._id.toString()) { return res.status(403).json({ message: 'Không có quyền tạo hotspot cho scene này' }); } const hotspot = new Hotspot({ parent_scene_id, target_scene_id, title, description, coordinates: { yaw: Number(coordinates?.yaw) || 0, pitch: Number(coordinates?.pitch) || 0 }, is_auto_return: false }); await hotspot.save(); // Logic tạo liên kết quay lại tự động nếu có scene đích if (target_scene_id) { const targetScene = await Scene.findById(target_scene_id); if (targetScene) { const reverseYaw = calculateReverseYaw(coordinates.yaw); const reverseHotspot = new Hotspot({ parent_scene_id: target_scene_id, target_scene_id: parent_scene_id, title: `Quay lại ${parentScene.name || parentScene.title}`, coordinates: { yaw: reverseYaw, pitch: 0 }, is_auto_return: true }); await reverseHotspot.save(); } } res.status(201).json(hotspot); } catch (error) { res.status(500).json({ message: error.message }); } }); /** * @route PUT /api/hotspots/update/:id * @desc Cập nhật thông tin/vị trí hotspot */ router.put('/update/:id', protect, async (req, res) => { try { const { title, description, coordinates } = req.body; const hotspot = await Hotspot.findById(req.params.id); if (!hotspot) return res.status(404).json({ message: 'Hotspot không tồn tại' }); const parentScene = await Scene.findById(hotspot.parent_scene_id); if (parentScene.createdBy.toString() !== req.user._id.toString()) { return res.status(403).json({ message: 'Không có quyền cập nhật' }); } if (title) hotspot.title = title; if (description) hotspot.description = description; if (coordinates) hotspot.coordinates = coordinates; await hotspot.save(); res.json(hotspot); } catch (error) { res.status(500).json({ message: error.message }); } }); /** * @route DELETE /api/hotspots/delete/:id * @desc Xóa hotspot và liên kết quay lại tự động nếu có */ router.delete('/delete/:id', protect, async (req, res) => { try { const hotspot = await Hotspot.findById(req.params.id); if (!hotspot) return res.status(404).json({ message: 'Hotspot không tồn tại' }); const parentScene = await Scene.findById(hotspot.parent_scene_id); if (parentScene.createdBy.toString() !== req.user._id.toString()) { return res.status(403).json({ message: 'Không có quyền xóa' }); } // Xóa liên kết ngược nếu đây là cặp đôi tự động tạo if (hotspot.target_scene_id) { await Hotspot.deleteOne({ parent_scene_id: hotspot.target_scene_id, target_scene_id: hotspot.parent_scene_id, is_auto_return: true }); } await Hotspot.findByIdAndDelete(req.params.id); res.json({ message: 'Hotspot deleted successfully' }); } catch (error) { res.status(500).json({ message: error.message }); } }); module.exports = router;