const request = require('supertest');
const mongoose = require('mongoose');
const fs = require('fs');
const path = require('path');
const Scene = require('../models/Scene');
const Asset = require('../models/Asset');
const Hotspot = require('../models/Hotspot');
const User = require('../models/User');

// Mock fs để không xóa file thật trong quá trình test và kiểm tra số lần gọi hàm
jest.mock('fs', () => ({
    ...jest.requireActual('fs'),
    promises: {
        unlink: jest.fn().mockResolvedValue()
    },
    existsSync: jest.fn().mockReturnValue(true)
}));

// Import app - Giả định server.js của bạn export express app
// Nếu file khởi tạo app của bạn có tên khác, hãy điều chỉnh đường dẫn bên dưới
const app = require('../server'); 

describe('Integration Test: Cascade Scene Deletion (BFS)', () => {
    let adminToken;
    let adminUser;
    let parentAsset, childAsset;
    let parentScene, childScene;

    beforeAll(async () => {
        // Kết nối tới Database Test (Sử dụng biến môi trường hoặc mặc định)
        if (mongoose.connection.readyState === 0) {
            await mongoose.connect(process.env.MONGO_URI || 'mongodb://localhost:27017/3dtours_test');
        }

        // Thiết lập Admin User để thực hiện các request có quyền bảo mật
        await User.deleteMany({});
        adminUser = await User.create({
            fullName: 'Admin Test',
            username: 'admintest',
            email: 'admin@test.com',
            password: 'password123',
            role: 'admin',
            agreedToRules: true
        });

        // Đăng nhập để lấy JWT Token
        const res = await request(app)
            .post('/api/auth/login')
            .send({ username: 'admintest', password: 'password123' });
        adminToken = res.body.token;
    });

    afterAll(async () => {
        await User.deleteMany({});
        await Scene.deleteMany({});
        await Asset.deleteMany({});
        await Hotspot.deleteMany({});
        await mongoose.connection.close();
    });

    beforeEach(async () => {
        jest.clearAllMocks();
        await Scene.deleteMany({});
        await Asset.deleteMany({});
        await Hotspot.deleteMany({});

        // 1. Tạo dữ liệu Scene Cha và Asset tương ứng
        parentAsset = await Asset.create({
            filePath: path.join(__dirname, '../uploads/parent_room.jpg'),
            fileSize: 1024 * 1024,
            uploadedBy: adminUser._id
        });
        parentScene = await Scene.create({
            name: 'Phòng Khách (Cha)',
            assetId: parentAsset._id,
            createdBy: adminUser._id,
            status: 'completed'
        });

        // 2. Tạo dữ liệu Scene Con và Asset tương ứng
        childAsset = await Asset.create({
            filePath: path.join(__dirname, '../uploads/child_balcony.jpg'),
            fileSize: 800 * 1024,
            uploadedBy: adminUser._id
        });
        childScene = await Scene.create({
            name: 'Ban Công (Con)',
            assetId: childAsset._id,
            createdBy: adminUser._id,
            status: 'completed'
        });

        // 3. Tạo liên kết: Cha -> trỏ tới -> Con thông qua Hotspot
        await Hotspot.create({
            parent_scene_id: parentScene._id,
            target_scene_id: childScene._id,
            title: 'Đi ra Ban Công'
        });
    });

    test('Khi xóa scene CHA, phải xóa dây chuyền sang scene CON và gỡ bỏ toàn bộ file vật lý', async () => {
        const res = await request(app)
            .delete(`/api/scenes/${parentScene._id}`)
            .set('Authorization', `Bearer ${adminToken}`);

        expect(res.status).toBe(200);

        // Kiểm tra Database: Không còn bất kỳ scene nào
        const scenesInDB = await Scene.find({});
        expect(scenesInDB.length).toBe(0);

        // Kiểm tra Assets: Các bản ghi asset cũng phải bị xóa sạch
        const assetsInDB = await Asset.find({});
        expect(assetsInDB.length).toBe(0);

        // Kiểm tra Filesystem: Phải gọi lệnh xóa (unlink) cho cả 2 tệp tin (cha và con)
        expect(fs.promises.unlink).toHaveBeenCalledTimes(2);
    });

    test('Khi xóa scene CON, scene CHA vẫn phải tồn tại (Không được xóa ngược)', async () => {
        const res = await request(app)
            .delete(`/api/scenes/${childScene._id}`)
            .set('Authorization', `Bearer ${adminToken}`);

        expect(res.status).toBe(200);

        // Scene Cha và Asset của nó phải còn nguyên trong Database
        const parentInDB = await Scene.findById(parentScene._id);
        expect(parentInDB).not.toBeNull();
        
        const parentAssetInDB = await Asset.findById(parentAsset._id);
        expect(parentAssetInDB).not.toBeNull();

        // Chỉ có 1 tệp tin bị xóa (tệp của scene con)
        expect(fs.promises.unlink).toHaveBeenCalledTimes(1);
        expect(fs.promises.unlink).toHaveBeenCalledWith(expect.stringContaining('child_balcony.jpg'));
    });
});