import { Request, Response } from 'express';
import * as dataSheetService from '../services/dataSheetService.js';
import fs from 'fs';
import * as pdfExtractionService from '../services/pdfExtractionService.js';
import { IAppUser } from '../middleware/roleMiddleware.js';
import { notificationService } from '../services/notificationService.js';

interface AuthRequest extends Request {
    appUser?: IAppUser;
}

export const getAllDataSheets = async (req: AuthRequest, res: Response) => {
    try {
        const organizationId = req.appUser?.organizationId;
        console.log('Backend: Fetching datasheets for org:', organizationId);
        const sheets = await dataSheetService.getAllDataSheets(organizationId);
        console.log(`Backend: Found ${sheets.length} sheets`);
        res.json(sheets);
    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        res.status(500).json({ error: message });
    }
};

export const extractData = async (req: AuthRequest, res: Response) => {
    try {
        const file = req.file;
        if (!file) {
            return res.status(400).json({ error: 'File is required' });
        }

        const fileBuffer = fs.readFileSync(file.path);
        const data = await pdfExtractionService.extractDataFromPdf(fileBuffer);

        // Return extracted data AND the file path so we don't need to re-upload
        res.json({
            ...data,
            tempFilePath: file.path
        });

    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        res.status(500).json({ error: message });
    }
};


export const createDataSheet = async (req: AuthRequest, res: Response) => {
    try {
        const file = req.file;
        const {
            name, manufacturer, type, solidsVolume, density,
            mixingRatio, mixingRatioWeight, mixingRatioVolume,
            yieldTheoretical, dftReference, yieldFactor,
            wftMin, wftMax, dftMin, dftMax, reducer, dilution,
            notes, fileUrl,
            manufacturerCode, minStock, typicalApplication
        } = req.body;
        const organizationId = req.appUser?.organizationId;

        // Note: New logic prefers 'file' upload which we store in DB.
        // If fileUrl is provided (legacy or external link), we use that but don't store binary.

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        let fileId: any = undefined;
        let finalFileUrl = fileUrl || '';

        if (file) {
            // Read file buffer
            const buffer = fs.readFileSync(file.path);

            // Save to StoredFile collection
            const { default: StoredFile } = await import('../models/StoredFile.js');
            const newFile = await StoredFile.create({
                filename: file.originalname,
                contentType: file.mimetype,
                data: buffer,
                size: file.size,
                uploadDate: new Date()
            });

            fileId = newFile._id;
            finalFileUrl = newFile._id.toString(); // Use ID as URL reference for consistency with frontend expectations if possible, or we might need to adjust frontend to use /api/datasheets/file/:id

            // Clean up temp file
            try {
                fs.unlinkSync(file.path);
            } catch (error) {
                console.warn('Failed to delete temp file:', file.path, error);
            }
        }

        if (!fileId && !finalFileUrl) {
            // Check if fileUrl allows empty. The schema says optional now, but logically a datasheet usually has a file.
            // However, for simplified Diluent registration, we might not have one.
            // If the user didn't send a file and didn't send a URL, and schema is optional, we can proceed.
            // But let's check if we want to enforce it.
            // If manufacturerCode (Diluent indicator?) is present, maybe skip check?
            // Actually, I removed 'required' from schema, so I should probably relax this check too.
            // return res.status(400).json({ error: 'File is required' });
        }

        const newSheet = await dataSheetService.createDataSheet({
            name,
            manufacturer,
            manufacturerCode,
            type,
            minStock: minStock ? Number(minStock) : undefined,
            typicalApplication,
            fileUrl: finalFileUrl,
            fileId: fileId,
            solidsVolume: solidsVolume ? Number(solidsVolume) : undefined,
            density: density ? Number(density) : undefined,
            mixingRatio,
            mixingRatioWeight,
            mixingRatioVolume,
            yieldTheoretical: yieldTheoretical ? Number(yieldTheoretical) : undefined,
            dftReference: dftReference ? Number(dftReference) : undefined,
            yieldFactor: yieldFactor ? Number(yieldFactor) : undefined,
            wftMin: wftMin ? Number(wftMin) : undefined,
            wftMax: wftMax ? Number(wftMax) : undefined,
            dftMin: dftMin ? Number(dftMin) : undefined,
            dftMax: dftMax ? Number(dftMax) : undefined,
            reducer,
            dilution: dilution ? Number(dilution) : undefined,
            notes,
            organizationId
        });

        // Notificação de Nova Ficha Técnica
        if (organizationId) {
            await notificationService.create({
                organizationId,
                title: 'Nova Ficha Técnica',
                message: `A ficha técnica "${name}" (${manufacturer}) foi adicionada à biblioteca.`,
                type: 'info',
                metadata: { dataSheetId: newSheet._id, triggerType: 'datasheet_created' }
            });
        }

        res.status(201).json(newSheet);
    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        console.error('Error creating datasheet:', error);
        res.status(500).json({ error: message });
    }
};

export const deleteDataSheet = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const organizationId = req.appUser?.organizationId;

        // Find sheet to delete file if exists
        // (Optional: Implement file deletion logic here if strict cleanup needed)

        const success = await dataSheetService.deleteDataSheet(id as string, organizationId);
        if (success) {
            res.status(204).send();
        } else {
            res.status(404).json({ error: 'Data sheet not found' });
        }
    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        res.status(500).json({ error: message });
    }
};

export const updateDataSheet = async (req: AuthRequest, res: Response) => {
    try {
        const id = req.params.id as string;
        const file = req.file;
        const organizationId = req.appUser?.organizationId;
        const {
            name, manufacturer, type, solidsVolume, density,
            mixingRatio, mixingRatioWeight, mixingRatioVolume,
            yieldTheoretical, dftReference, yieldFactor,
            wftMin, wftMax, dftMin, dftMax, reducer, dilution,
            notes, fileUrl
        } = req.body;

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const updates: Record<string, any> = {
            name,
            manufacturer,
            type,
            notes,
            solidsVolume: solidsVolume ? Number(solidsVolume) : undefined,
            density: density ? Number(density) : undefined,
            yieldTheoretical: yieldTheoretical ? Number(yieldTheoretical) : undefined,
            dftReference: dftReference ? Number(dftReference) : undefined,
            yieldFactor: yieldFactor ? Number(yieldFactor) : undefined,
            wftMin: wftMin ? Number(wftMin) : undefined,
            wftMax: wftMax ? Number(wftMax) : undefined,
            dftMin: dftMin ? Number(dftMin) : undefined,
            dftMax: dftMax ? Number(dftMax) : undefined,
            reducer,
            dilution: dilution ? Number(dilution) : undefined,
            mixingRatio,
            mixingRatioWeight,
            mixingRatioVolume
        };

        if (file) {
            // Read file buffer
            const buffer = fs.readFileSync(file.path);

            // Save to StoredFile collection
            const { default: StoredFile } = await import('../models/StoredFile.js');
            const newFile = await StoredFile.create({
                filename: file.originalname,
                contentType: file.mimetype,
                data: buffer,
                size: file.size,
                uploadDate: new Date()
            });

            updates.fileId = newFile._id;
            updates.fileUrl = newFile._id.toString();

            // Clean up temp file
            try {
                fs.unlinkSync(file.path);
            } catch (error) {
                console.warn('Failed to delete temp file:', file.path, error);
            }
        } else if (fileUrl) {
            updates.fileUrl = String(fileUrl);
            // If fileUrl is being updated but not file, we might lose fileId reference? 
            // If the user sends the same fileUrl (which is the ID), it's fine.
            // But if they send a new external URL, we should probably unset fileId.
            // For now, let's assume if it's an external URL, fileId should remain unless explicitly cleared?
            // Safer: if fileUrl is explicitly sent and doesn't match an ID format, maybe clear fileId?
            // Actually, keep it simple.
        }

        const updatedSheet = await dataSheetService.updateDataSheet(id, updates, organizationId);

        if (updatedSheet) {
            res.json(updatedSheet);
        } else {
            res.status(404).json({ error: 'Data sheet not found' });
        }
    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        console.error('Error updating datasheet:', error);
        res.status(500).json({ error: message });
    }
};

export const getFile = async (req: Request, res: Response) => {
    try {
        const id_or_filename = req.params.id as string;

        // Check if it's a MongoDB ObjectId (24 hex chars)
        if (/^[0-9a-fA-F]{24}$/.test(id_or_filename)) {
            const { default: StoredFile } = await import('../models/StoredFile.js');
            const fileDoc = await StoredFile.findById(id_or_filename);

            if (fileDoc) {
                res.set('Content-Type', fileDoc.contentType || 'application/pdf');
                res.set('Content-Disposition', `inline; filename="${fileDoc.filename}"`);
                res.set('Access-Control-Allow-Origin', '*');
                res.set('Cache-Control', 'public, max-age=3600');
                return res.send(fileDoc.data);
            }
        }

        // Fallback to file system (legacy)
        const stream = dataSheetService.getFileStream(id_or_filename);

        stream.on('file', (file) => {
            res.set('Content-Type', 'application/pdf');
            res.set('Content-Disposition', `inline; filename="${file.filename}"`);
        });

        stream.on('error', () => {
            res.status(404).json({ error: 'File not found' });
        });

        stream.pipe(res);
    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        console.error('Error getting file:', error);
        res.status(500).json({ error: message });
    }
};
