import TechnicalDataSheet from '../models/TechnicalDataSheet.js';
import fs from 'fs';
import path from 'path';
import { bucket } from '../config/database.js';
import { ObjectId } from 'mongodb';

export const saveFileToGridFS = (localPath: string, filename: string): Promise<string> => {
    return new Promise((resolve, reject) => {
        const uploadStream = bucket.openUploadStream(filename);
        const readStream = fs.createReadStream(localPath);

        readStream.pipe(uploadStream)
            .on('error', reject)
            .on('finish', () => {
                // Remove local file after upload
                fs.unlink(localPath, (err) => {
                    if (err) console.error('Failed to delete local temp file:', err);
                });
                resolve(uploadStream.id.toString());
            });
    });
};

export const deleteFileFromGridFS = async (fileId: string) => {
    try {
        await bucket.delete(new ObjectId(fileId));
        return true;
    } catch (err) {
        console.error('Failed to delete file from GridFS:', err);
        return false;
    }
};

export const getFileStream = (fileId: string) => {
    if (!ObjectId.isValid(fileId)) {
        throw new Error('Invalid file ID format');
    }
    return bucket.openDownloadStream(new ObjectId(fileId));
};

export const getAllDataSheets = async (organizationId?: string) => {
    const query = organizationId
        ? { $or: [{ organizationId }, { organizationId: { $exists: false } }, { organizationId: null }] }
        : {};
    const sheets = await TechnicalDataSheet.find(query).sort({ uploadDate: -1 }).lean();
    return sheets.map(s => ({ ...s, id: s._id.toString() }));
};

export const matchSheets = async (query: string, organizationId?: string) => {
    const orgFilter = organizationId
        ? { $or: [{ organizationId }, { organizationId: { $exists: false } }, { organizationId: null }] }
        : {};

    const filter = {
        ...orgFilter,
        $or: [
            { name: { $regex: query, $options: 'i' } },
            { manufacturer: { $regex: query, $options: 'i' } },
            { type: { $regex: query, $options: 'i' } }
        ]
    };
    const sheets = await TechnicalDataSheet.find(filter).lean();
    return sheets.map(s => ({ ...s, id: s._id.toString() }));
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const createDataSheet = async (data: any & { organizationId?: string }) => {
    let fileId = data.fileUrl;

    // If fileUrl is a local path (exists on disk), move to GridFS
    if (data.fileUrl && fs.existsSync(data.fileUrl)) {
        fileId = await saveFileToGridFS(data.fileUrl, data.name + '.pdf');
    }

    const newSheet = new TechnicalDataSheet({
        ...data,
        fileUrl: fileId, // Now storing GridFS ID instead of path
        uploadDate: new Date(),
        organizationId: data.organizationId
    });

    const saved = await newSheet.save();
    return { ...saved.toObject(), id: saved._id.toString() };
};

export const deleteDataSheet = async (id: string, organizationId?: string) => {
    // Find first to check permissions
    const sheet = await TechnicalDataSheet.findById(id);
    if (!sheet) return false;

    // Permission Check:
    // If current user is in an Org, and Sheet is in a DIFFERENT Org, deny.
    // Explicitly allow if Sheet has NO Org (Legacy/Global).
    if (organizationId && sheet.organizationId && sheet.organizationId !== organizationId) {
        console.warn(`[Delete DataSheet] Access Denied. User Org: ${organizationId}, Sheet Org: ${sheet.organizationId}`);
        return false;
    }

    // Delete from GridFS if not a full URL
    if (sheet.fileUrl && !sheet.fileUrl.startsWith('http')) {
        await deleteFileFromGridFS(sheet.fileUrl);
    }

    await TechnicalDataSheet.findByIdAndDelete(id);
    return true;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const updateDataSheet = async (id: string, updates: any, organizationId?: string) => {
    // SECURITY FIX: Allow update if:
    // 1. Matches ID AND Matches Organization
    // 2. OR Matches ID AND Record has NO organization (legacy/orphan) -> Adopt it!

    const oldSheet = await TechnicalDataSheet.findById(id);
    if (!oldSheet) return null;

    if (organizationId && oldSheet.organizationId && oldSheet.organizationId !== organizationId) {
        console.warn(`Access Denied: Sheet ${id} belongs to ${oldSheet.organizationId}, user is ${organizationId}`);
        return null; // Return null effectively hides it or acts as fail
    }

    // If new file is uploaded (path exists locally)
    if (updates.fileUrl && updates.fileUrl !== oldSheet.fileUrl && fs.existsSync(updates.fileUrl)) {
        // Upload new file
        const newFileId = await saveFileToGridFS(updates.fileUrl, (updates.name || oldSheet.name) + '.pdf');

        // Delete old file from GridFS
        if (oldSheet.fileUrl && !oldSheet.fileUrl.startsWith('http')) {
            await deleteFileFromGridFS(oldSheet.fileUrl);
        }

        updates.fileUrl = newFileId;
    }

    if (organizationId && !oldSheet.organizationId) {
        updates.organizationId = organizationId;
    }

    const updated = await TechnicalDataSheet.findOneAndUpdate({ _id: id }, updates, { new: true }).lean();
    if (updated) {
        return { ...updated, id: updated._id.toString() };
    }
    return null;
};

export const migrateFilesToGridFS = async () => {
    try {
        const sheets = await TechnicalDataSheet.find({ fileUrl: { $regex: /^uploads\// } });
        console.log(`[MIGRATION] Found ${sheets.length} sheets to migrate to GridFS`);

        for (const sheet of sheets) {
            const localPath = path.join(process.cwd(), sheet.fileUrl);
            if (fs.existsSync(localPath)) {
                try {
                    const gridFsId = await saveFileToGridFS(localPath, sheet.name + '.pdf');
                    sheet.fileUrl = gridFsId;
                    await sheet.save();
                    console.log(`[MIGRATION] Successfully migrated: ${sheet.name}`);
                } catch (err) {
                    console.error(`[MIGRATION] Error migrating ${sheet.name}:`, err);
                }
            } else {
                console.warn(`[MIGRATION] File not found for ${sheet.name}: ${localPath}`);
            }
        }
    } catch (error) {
        console.error('[MIGRATION] Migration failed:', error);
    }
};




