const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');

const User = require('../models/User');
const Asset = require('../models/Asset');
const Scene = require('../models/Scene');
const Hotspot = require('../models/Hotspot'); // Giả định bạn đã tạo model mới

const { protect, optionalAuth } = require('../middlewares/authMiddleware');
const { verifyReferer, setNoCacheHeaders } = require('../middlewares/securityMiddleware');
const { resizeTo8K } = require('../utils/imageHelper');
const { getGPSCoordinates, injectGPSCoordinates } = require('../utils/exifHelper');

const router = express.Router();

// Ensure upload directories exist
const uploadDir = path.join(__dirname, '../uploads');
const tempDir = path.join(uploadDir, 'temp');
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true });

// Configure Multer for temp uploads
const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, tempDir);
    },
    filename: (req, file, cb) => {
        cb(null, `${Date.now()}_${crypto.randomBytes(4).toString('hex')}${path.extname(file.originalname)}`);
    }
});

const upload = multer({
    storage: storage,
    fileFilter: (req, file, cb) => {
        // Only accept images
        if (file.mimetype.startsWith('image/')) {
            cb(null, true);
        } else {
            cb(new Error('Only image files are allowed!'), false);
        }
    }
});

/**
 * Wrapper for Multer middleware to catch "Request aborted" and other upload errors gracefully.
 */
const uploadSinglePanorama = (req, res, next) => {
    const multerUpload = upload.single('panorama');
    multerUpload(req, res, (err) => {
        if (err) {
            // Bắt lỗi khi client ngắt kết nối đột ngột
            if (err.message === 'Request aborted') {
                console.warn(`[Multer Warning]: Upload aborted by client at ${req.method} ${req.originalUrl}`);
                return res.status(499).json({ message: 'Client aborted the request' });
            }
            if (err instanceof multer.MulterError) {
                return res.status(400).json({ message: `Multer error: ${err.message}` });
            }
            return res.status(400).json({ message: err.message });
        }
        next();
    });
};

/**
 * @route   POST /api/scenes
 * @desc    Create a new 3D scene (with 360 photo, 8K resize, EXIF injection)
 * @access  Private (Registered Users)
 */
router.post('/scenes', protect, uploadSinglePanorama, async (req, res) => {
    try {
        const { title, lat, lng, privacy, sharedWithUsers } = req.body;
        
        if (!req.file) {
            return res.status(400).json({ message: 'Please upload a panorama image' });
        }

        const latitude = Number(lat);
        const longitude = Number(lng);

        if (isNaN(latitude) || isNaN(longitude)) {
            // Cleanup uploaded file on validation error
            fs.unlinkSync(req.file.path);
            return res.status(400).json({ message: 'Valid lat and lng are required' });
        }

        const tempFilePath = req.file.path;
        const processedFileName = `processed_${req.file.filename}.jpg`;
        const processedFilePath = path.join(uploadDir, processedFileName);

        // Lấy tọa độ GPS gốc từ ảnh vừa upload trước khi nén/xử lý
        const originalGPS = await getGPSCoordinates(tempFilePath);

        // BACKGROUND PROCESSING: Thực hiện song song không chặn response
        setImmediate(async () => {
            try {
                // 1. Resize to 8K
                await resizeTo8K(tempFilePath, processedFilePath);
                // 2. Inject GPS
                await injectGPSCoordinates(processedFilePath, latitude, longitude);
                // 3. Cleanup temp file
                if (fs.existsSync(tempFilePath)) fs.unlinkSync(tempFilePath);
                console.log(`Background processing finished for: ${processedFileName}`);
            } catch (err) {
                console.error(`Background Image processing failed: ${err.message}`);
            }
        });

        // 5. Save Asset to DB
        const asset = new Asset({
            filePath: processedFilePath,
            uploadedBy: req.user._id,
            coordinates: originalGPS ? { lat: originalGPS.lat, lng: originalGPS.lng } : { lat: latitude, lng: longitude }
        });
        await asset.save();

        // 6. Handle share token if privacy is 'shared'
        let shareToken = undefined;
        if (privacy === 'shared') {
            shareToken = crypto.randomBytes(24).toString('hex');
        }

        // Handle sharedWith User IDs
        let parsedSharedWith = [];
        if (sharedWithUsers) {
            try {
                parsedSharedWith = JSON.parse(sharedWithUsers);
            } catch (e) {
                // Ignore parse error
            }
        }

        // 7. Save Scene to DB
        const scene = new Scene({
            name: title,
            assetId: asset._id,
            scene_url: processedFilePath, // Lưu đường dẫn ảnh trực tiếp
            gps: {
                lat: latitude,
                lng: longitude
            },
            createdBy: req.user._id,
            privacy: privacy || 'private',
            shareToken,
            sharedWith: parsedSharedWith
        });
        await scene.save();

        res.status(202).json({
            message: 'Scene created successfully',
            scene
        });

    } catch (error) {
        // Cleanup file if error occurs
        if (req.file && fs.existsSync(req.file.path)) {
            try { fs.unlinkSync(req.file.path); } catch (e) {}
        }
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   GET /api/scenes
 * @desc    Get all accessible scenes for the map (respecting privacy rules)
 * @access  Public / Private
 */
router.get('/scenes', optionalAuth, async (req, res) => {
    try {
        console.log(`[Data Load] Bắt đầu truy vấn scenes cho: ${req.user ? req.user._id : 'Khách'}`);
        let query = {};

        if (req.user) {
            // Logged in: See public, member-only, owned, or shared-with-me scenes
            query = {
                $or: [
                    { privacy: 'public' },
                    { privacy: 'member' },
                    { privacy: 'shared' }, // shareToken will be required to fetch panorama, but coordinates show on map
                    { createdBy: req.user._id },
                    { sharedWith: req.user._id }
                ]
            };
        } else {
            // Guests: See only public or shared scenes
            query = {
                $or: [
                    { privacy: 'public' },
                    { privacy: 'shared' }
                ]
            };
        }

        const scenes = await Scene.find(query)
            .populate('createdBy', 'username')
            .lean();

        console.log(`[Data Load] Đã tìm thấy ${scenes.length} scenes. Gửi phản hồi về Frontend...`);
        res.json(scenes);
    } catch (error) {
        console.error(`[Data Load Error]: ${error.stack}`);
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   GET /api/scenes/:id
 * @desc    Get single scene detail (respecting privacy rules)
 * @access  Public / Private
 */
router.get('/scenes/:id', optionalAuth, async (req, res) => {
    try {
        const scene = await Scene.findById(req.params.id)
            .populate('createdBy', 'username')
            .populate('assetId');

        if (!scene) {
            return res.status(404).json({ message: 'Scene not found' });
        }

        const hasAccess = 
            scene.privacy === 'public' ||
            (scene.privacy === 'member' && req.user) ||
            (req.user && scene.createdBy._id.toString() === req.user._id.toString()) ||
            (req.user && scene.sharedWith.includes(req.user._id)) ||
            (scene.privacy === 'shared' && req.query.token === scene.shareToken);

        if (!hasAccess) {
            return res.status(403).json({ message: 'Access denied to this scene' });
        }

        res.json(scene);
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   GET /api/hotspots/:scene_id
 * @desc    Lấy toàn bộ danh sách hotspot của scene hiện tại
 */
router.get('/hotspots/:scene_id', async (req, res) => {
    try {
        const hotspots = await Hotspot.find({ parent_scene_id: req.params.scene_id });
        res.json(hotspots);
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   POST /api/hotspots/create
 * @desc    Tạo mới Hotspot + Tự động tạo liên kết ngược
 */
router.post('/hotspots/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);
        // Phân quyền: Admin hoặc Người tạo Scene
        const isAuthorized = req.user.role === 'Chủ sở hữu' || (parentScene && parentScene.createdBy.toString() === req.user._id.toString());
        if (!parentScene || !isAuthorized) {
            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),
                pitch: Number(coordinates.pitch)
            },
            is_auto_return: false
        });
        await hotspot.save();

        if (target_scene_id) {
            const targetScene = await Scene.findById(target_scene_id);
            if (targetScene) {
                const reverseYaw = coordinates.yaw > 0 ? coordinates.yaw - 180 : coordinates.yaw + 180;
                
                // Fallback đa tầng cho tiêu đề quay lại
                const backLabel = title || parentScene.name || parentScene.title || 'cảnh trước';

                const reverseHotspot = new Hotspot({
                    parent_scene_id: target_scene_id,
                    target_scene_id: parent_scene_id,
                    title: `Quay lại ${backLabel}`,
                    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 hotspot
 */
router.put('/hotspots/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);
        // Phân quyền Admin hoặc Owner
        const isAuthorized = req.user.role === 'Chủ sở hữu' || (parentScene && parentScene.createdBy.toString() === req.user._id.toString());
        if (!isAuthorized) {
            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 = {
                yaw: Number(coordinates.yaw),
                pitch: Number(coordinates.pitch)
            };
        }

        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 + Xóa luôn hotspot ngược tương ứng
 */
router.delete('/hotspots/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);
        // Phân quyền Admin hoặc Owner
        const isAuthorized = req.user.role === 'Chủ sở hữu' || (parentScene && parentScene.createdBy.toString() === req.user._id.toString());
        if (!isAuthorized) {
            return res.status(403).json({ message: 'Không có quyền xóa' });
        }

        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 });
    }
});

/**
 * @route   GET /api/assets/view/:assetId
 * @desc    Securely stream panorama images (prevents direct link / unauthorized downloads)
 * @access  Public / Private + Referer Verification + Token validation
 */
router.get('/assets/view/:assetId', verifyReferer, optionalAuth, async (req, res) => {
    try {
        const asset = await Asset.findById(req.params.assetId);
        if (!asset) {
            return res.status(404).json({ message: 'Asset not found' });
        }

        // Find associated scene to verify privacy
        const scene = await Scene.findOne({ assetId: asset._id });
        if (!scene) {
            // Orphaned asset, only owner can view
            if (!req.user || req.user._id.toString() !== asset.uploadedBy.toString()) {
                return res.status(403).json({ message: 'Access denied' });
            }
        } else {
            const hasAccess = 
                scene.privacy === 'public' ||
                (scene.privacy === 'member' && req.user) ||
                (req.user && scene.createdBy.toString() === req.user._id.toString()) ||
                (req.user && scene.sharedWith.includes(req.user._id)) ||
                (scene.privacy === 'shared' && req.query.token === scene.shareToken);

            if (!hasAccess) {
                return res.status(403).json({ message: 'Access denied: You do not have permission to view this asset' });
            }
        }

        if (!fs.existsSync(asset.filePath)) {
            return res.status(404).json({ message: 'Physical file not found on disk' });
        }

        const resolvedPath = path.resolve(asset.filePath);
        
        // Sử dụng res.sendFile để tối ưu hóa việc truyền tải file lớn và hỗ trợ Caching (ETag)
        res.sendFile(resolvedPath, {
            maxAge: 2592000000, // 30 ngày (tính bằng ms)
            lastModified: true,
            headers: {
                'Content-Type': 'image/jpeg',
                'Content-Disposition': 'inline; filename="panorama.jpg"',
                'Cache-Control': 'public, max-age=2592000, immutable' // Buộc trình duyệt lấy từ cache mà không cần hỏi lại server
            }
        });

    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   PUT /api/scenes/:id
 * @desc    Update an existing scene
 * @access  Private (Owner only)
 */
router.put('/scenes/:id', protect, uploadSinglePanorama, async (req, res) => {
    try {
        const { title, privacy, sharedWithUsers, lat, lng } = req.body;
        const scene = await Scene.findById(req.params.id);

        // Phân quyền Admin hoặc Owner
        const isAuthorized = req.user.role === 'Chủ sở hữu' || (scene && scene.createdBy.toString() === req.user._id.toString());
        if (!scene || !isAuthorized) {
            return res.status(403).json({ message: 'Not authorized' });
        }

        // Update basic info
        scene.name = title || scene.name;
        scene.privacy = privacy || scene.privacy;
        if (lat) scene.gps.lat = Number(lat);
        if (lng) scene.gps.lng = Number(lng);

        if (privacy === 'shared' && !scene.shareToken) {
            scene.shareToken = crypto.randomBytes(24).toString('hex');
        }

        // Update image if new one is uploaded
        if (req.file) {
            const processedFileName = `processed_${req.file.filename}.jpg`;
            const processedFilePath = path.join(uploadDir, processedFileName);

            await resizeTo8K(req.file.path, processedFilePath);
            await injectGPSCoordinates(processedFilePath, scene.lat, scene.lng);
            
            const asset = new Asset({
                filePath: processedFilePath,
                uploadedBy: req.user._id
            });
            await asset.save();
            scene.assetId = asset._id;

            if (fs.existsSync(req.file.path)) fs.unlinkSync(req.file.path);
        }

        await scene.save();
        res.json({ message: 'Scene updated', scene });
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   DELETE /api/scenes/:id
 * @desc    Delete a scene and its assets
 * @access  Private (Owner only)
 */
router.delete('/scenes/:id', protect, async (req, res) => {
    try {
        const scene = await Scene.findById(req.params.id);
        // Phân quyền Admin hoặc Owner
        const isAuthorized = req.user.role === 'Chủ sở hữu' || (scene && scene.createdBy.toString() === req.user._id.toString());
        if (!scene || !isAuthorized) {
            return res.status(403).json({ message: 'Not authorized' });
        }

        // Delete physical file if exists
        const asset = await Asset.findById(scene.assetId);
        if (asset && fs.existsSync(asset.filePath)) {
            fs.unlinkSync(asset.filePath);
        }

        await Asset.findByIdAndDelete(scene.assetId);
        await Scene.findByIdAndDelete(req.params.id);

        res.json({ message: 'Scene deleted successfully' });
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});

/**
 * @route   POST /api/maintenance/reset-all
 * @desc    Wipe all scenes, assets, and physical files (DANGEROUS: For dev reset only)
 * @access  Private (Owner only)
 */
router.post('/maintenance/reset-all', protect, async (req, res) => {
    try {
        // 1. Xóa toàn bộ dữ liệu trong Database
        await Scene.deleteMany({});
        await Asset.deleteMany({});
        // Lưu ý: Không xóa Users trừ khi bạn muốn reset cả tài khoản

        // 2. Dọn dẹp thư mục uploads (trừ các file .gitkeep hoặc thư mục temp)
        const files = fs.readdirSync(uploadDir);
        for (const file of files) {
            const fullPath = path.join(uploadDir, file);
            if (fs.lstatSync(fullPath).isFile()) {
                fs.unlinkSync(fullPath);
            }
        }

        // 3. Dọn dẹp thư mục temp
        const tempFiles = fs.readdirSync(tempDir);
        for (const file of tempFiles) {
            const fullPath = path.join(tempDir, file);
            if (fs.lstatSync(fullPath).isFile()) {
                fs.unlinkSync(fullPath);
            }
        }

        console.warn(`[Maintenance]: Toàn bộ dữ liệu tour đã bị xóa bởi ${req.user.username}`);
        res.json({ message: 'Dữ liệu đã được xóa sạch. Hãy clear localStorage ở trình duyệt để bắt đầu lại.' });
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});

module.exports = router;
