const AssetService = require('../services/asset.service');
const Asset = require('../models/Asset');
const LabelService = require('../services/label.service');
const { asyncHandler } = require('../middleware/errorHandler');
const { getIntuneManagedDevices } = require('../services/graph.service');
const { ROLES, TECHNIKER_DEPARTMENTS } = require('../middleware/roleCheck');

// Returns department filter for the current user (null = all departments)
function getDeptFilter(user) {
    if (user.role === ROLES.TECHNIKER) return TECHNIKER_DEPARTMENTS;
    return null;
}

class AssetController {
    /**
     * Get all assets
     * GET /api/assets
     */
    static getAllAssets = asyncHandler(async (req, res) => {
        const departments = getDeptFilter(req.user);
        const assets = AssetService.getAllAssets(departments);

        res.json({
            status: 'success',
            data: assets
        });
    });

    /**
     * Get assets assigned to the current user
     * GET /api/assets/mine
     */
    static getMyAssets = asyncHandler(async (req, res) => {
        const assets = Asset.getByAssignedUser(req.user.id);
        res.json({ status: 'success', data: assets });
    });

    /**
     * Get asset by ID
     * GET /api/assets/:id
     */
    static getAssetById = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const asset = AssetService.getAssetById(parseInt(id));

        res.json({
            status: 'success',
            data: asset
        });
    });

    /**
     * Get asset by serial number
     * GET /api/assets/serial/:serialNumber
     */
    static getAssetBySerial = asyncHandler(async (req, res) => {
        const { serialNumber } = req.params;
        const asset = AssetService.getAssetBySerial(serialNumber);

        res.json({
            status: 'success',
            data: asset
        });
    });

    /**
     * Get assets by status
     * GET /api/assets/status/:status
     */
    static getAssetsByStatus = asyncHandler(async (req, res) => {
        const { status } = req.params;
        const assets = AssetService.getAssetsByStatus(status);

        res.json({
            status: 'success',
            data: assets
        });
    });

    /**
     * Get assets by type
     * GET /api/assets/type/:type
     */
    static getAssetsByType = asyncHandler(async (req, res) => {
        const { type } = req.params;
        const assets = AssetService.getAssetsByType(type);

        res.json({
            status: 'success',
            data: assets
        });
    });

    /**
     * Create new asset
     * POST /api/assets
     */
    static createAsset = asyncHandler(async (req, res) => {
        const asset = AssetService.createAsset(
            req.body,
            req.user.id,
            req.ip
        );

        res.status(201).json({
            status: 'success',
            data: asset
        });
    });

    /**
     * Update asset
     * PUT /api/assets/:id
     */
    static updateAsset = asyncHandler(async (req, res) => {
        const { id } = req.params;

        const asset = AssetService.updateAsset(
            parseInt(id),
            req.body,
            req.user.id,
            req.ip
        );

        res.json({
            status: 'success',
            data: asset
        });
    });

    /**
     * Delete asset
     * DELETE /api/assets/:id
     */
    static deleteAsset = asyncHandler(async (req, res) => {
        const { id } = req.params;

        const deleted = AssetService.deleteAsset(
            parseInt(id),
            req.user.id,
            req.ip
        );

        if (!deleted) {
            return res.status(404).json({
                status: 'error',
                message: 'Asset nicht gefunden'
            });
        }

        res.json({
            status: 'success',
            message: 'Asset erfolgreich gelöscht'
        });
    });

    /**
     * Assign asset to user
     * POST /api/assets/:id/assign
     */
    static assignAsset = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const { user_id, notes } = req.body;

        if (!user_id) {
            return res.status(400).json({
                status: 'error',
                message: 'Benutzer-ID ist erforderlich'
            });
        }

        const assignment = AssetService.assignAsset(
            parseInt(id),
            parseInt(user_id),
            req.user.id,
            notes,
            req.ip
        );

        // ANL-Nummer automatisch vergeben wenn noch keine vorhanden
        try {
            const Database = require('better-sqlite3');
            const db = new Database(process.env.DATABASE_PATH || './database.sqlite');
            const asset = db.prepare('SELECT inventory_number FROM assets WHERE id=?').get(parseInt(id));
            if (!asset?.inventory_number) {
                const maxRow = db.prepare("SELECT MAX(CAST(SUBSTR(inventory_number, 5) AS INTEGER)) as mx FROM assets WHERE inventory_number LIKE 'ANL-%'").get();
                const next = (maxRow?.mx || 0) + 1;
                const anl = `ANL-${String(next).padStart(4, '0')}`;
                db.prepare('UPDATE assets SET inventory_number=? WHERE id=?').run(anl, parseInt(id));
            }
            db.close();
        } catch (_) {}

        res.json({
            status: 'success',
            data: assignment
        });
    });

    /**
     * Unassign asset from user
     * POST /api/assets/:id/unassign
     */
    static unassignAsset = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const { new_status } = req.body;

        if (!new_status) {
            return res.status(400).json({
                status: 'error',
                message: 'Neuer Status ist erforderlich'
            });
        }

        const asset = AssetService.unassignAsset(
            parseInt(id),
            req.user.id,
            new_status,
            req.ip
        );

        res.json({
            status: 'success',
            data: asset
        });
    });

    /**
     * Get assignment history for an asset
     * GET /api/assets/:id/history
     */
    static getAssetAssignmentHistory = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const history = AssetService.getAssetAssignmentHistory(parseInt(id));

        res.json({
            status: 'success',
            data: history
        });
    });

    /**
     * Get asset statistics
     * GET /api/assets/stats
     */
    static getStatistics = asyncHandler(async (req, res) => {
        const departments = getDeptFilter(req.user);
        const stats = AssetService.getStatistics(departments);

        res.json({
            status: 'success',
            data: stats
        });
    });
    /**
     * Generate handover protocol PDF for an assigned asset
     * GET /api/assets/:id/handover-protocol
     */
    static generateHandoverProtocol = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const asset = AssetService.getAssetById(parseInt(id));

        if (!asset.assigned_to_user_id) {
            return res.status(400).json({
                status: 'error',
                message: 'Das Asset ist keinem Mitarbeiter zugewiesen'
            });
        }

        const PDFDocument = require('pdfkit');
        const doc = new PDFDocument({ size: 'A4', margin: 50 });

        const filename = `uebergabeprotokoll_${(asset.serial_number || asset.id).replace(/[^a-z0-9]/gi, '_')}.pdf`;
        res.set({
            'Content-Type': 'application/pdf',
            'Content-Disposition': `inline; filename="${filename}"`,
        });
        doc.pipe(res);

        const today = new Date().toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' });
        const BLUE = '#2563eb';
        const GRAY = '#6b7280';
        const BLACK = '#111827';
        const pageW = doc.page.width - 100; // usable width (margins 50 each side)

        // ── Header ────────────────────────────────────────────────────────────
        doc.fontSize(20).fillColor(BLUE).text('Cereda Systems GmbH', 50, 50);
        doc.fontSize(10).fillColor(GRAY).text('IT-Abteilung · IT-Nexus', 50, 75);
        doc.fontSize(16).fillColor(BLACK).text('Übergabeprotokoll', 50, 100);
        doc.fontSize(10).fillColor(GRAY).text(`Erstellt am: ${today}`, 50, 120);

        doc.moveTo(50, 140).lineTo(545, 140).strokeColor(BLUE).lineWidth(1.5).stroke();

        // ── Helper: draw a labeled row ────────────────────────────────────────
        const row = (label, value, y) => {
            doc.fontSize(9).fillColor(GRAY).text(label, 50, y);
            doc.fontSize(10).fillColor(BLACK).text(value || '—', 200, y);
        };

        // ── Asset-Informationen ───────────────────────────────────────────────
        let y = 160;
        doc.fontSize(12).fillColor(BLUE).text('Arbeitsmittel', 50, y);
        y += 20;
        row('Bezeichnung', asset.name, y); y += 18;
        row('Typ', asset.type, y); y += 18;
        row('Modell', asset.model, y); y += 18;
        row('Seriennummer', asset.serial_number, y); y += 18;
        row('Kaufdatum', asset.purchase_date
            ? new Date(asset.purchase_date).toLocaleDateString('de-DE')
            : null, y); y += 18;
        if (asset.description) { row('Beschreibung', asset.description, y); y += 18; }

        y += 10;
        doc.moveTo(50, y).lineTo(545, y).strokeColor('#e5e7eb').lineWidth(0.5).stroke();
        y += 15;

        // ── Mitarbeiter-Informationen ─────────────────────────────────────────
        doc.fontSize(12).fillColor(BLUE).text('Empfänger', 50, y);
        y += 20;

        const assignedName = [asset.assigned_to_first_name, asset.assigned_to_last_name]
            .filter(Boolean).join(' ') || asset.assigned_to_username || '—';
        row('Name', assignedName, y); y += 18;
        row('E-Mail', asset.assigned_to_email, y); y += 18;
        row('Übergabedatum', today, y); y += 18;

        y += 10;
        doc.moveTo(50, y).lineTo(545, y).strokeColor('#e5e7eb').lineWidth(0.5).stroke();
        y += 15;

        // ── Nutzungshinweis ───────────────────────────────────────────────────
        doc.fontSize(12).fillColor(BLUE).text('Nutzungshinweis', 50, y);
        y += 18;
        doc.fontSize(9).fillColor(GRAY).text(
            'Das übergebene Arbeitsmittel ist ausschließlich für dienstliche Zwecke zu verwenden. ' +
            'Es ist sachgerecht zu behandeln und vor Verlust, Beschädigung sowie unbefugtem Zugriff zu schützen. ' +
            'Defekte oder Verluste sind unverzüglich der IT-Abteilung zu melden (helpdesk@cereda-systems.de). ' +
            'Bei Austritt aus dem Unternehmen ist das Arbeitsmittel vollständig zurückzugeben.',
            50, y, { width: pageW, lineGap: 3 }
        );
        y += 70;

        doc.moveTo(50, y).lineTo(545, y).strokeColor('#e5e7eb').lineWidth(0.5).stroke();
        y += 20;

        // ── Unterschriften ────────────────────────────────────────────────────
        doc.fontSize(12).fillColor(BLUE).text('Unterschriften', 50, y);
        y += 30;

        const sigW = (pageW - 40) / 2;

        // Left: Mitarbeiter
        doc.fontSize(9).fillColor(GRAY).text('Mitarbeiter/in', 50, y);
        doc.moveTo(50, y + 40).lineTo(50 + sigW, y + 40).strokeColor(BLACK).lineWidth(0.8).stroke();
        doc.fontSize(8).fillColor(GRAY).text(`${assignedName}`, 50, y + 45);

        // Right: IT-Verantwortlicher
        const rightX = 50 + sigW + 40;
        doc.fontSize(9).fillColor(GRAY).text('IT-Verantwortliche/r', rightX, y);
        doc.moveTo(rightX, y + 40).lineTo(rightX + sigW, y + 40).strokeColor(BLACK).lineWidth(0.8).stroke();
        doc.fontSize(8).fillColor(GRAY).text('Cereda Systems GmbH · IT', rightX, y + 45);

        // ── Footer ────────────────────────────────────────────────────────────
        doc.fontSize(7).fillColor(GRAY)
            .text('Dieses Dokument wurde automatisch durch IT-Nexus generiert · SUP-006 Infrastruktur & Arbeitsmittel',
                50, doc.page.height - 40, { align: 'center', width: pageW });

        doc.end();
    });

    /**
     * Import managed devices from Microsoft Intune as assets
     * POST /api/assets/import/intune
     */
    static importFromIntune = asyncHandler(async (req, res) => {
        let devices;
        try {
            devices = await getIntuneManagedDevices();
        } catch (err) {
            return res.status(502).json({
                status: 'error',
                message: err.message
            });
        }

        const results = { imported: 0, skipped: 0, errors: [] };

        for (const device of devices) {
            try {
                const serial = (device.serialNumber || '').trim();
                if (!serial) {
                    results.skipped++;
                    continue;
                }

                // Skip if already exists by serial number
                const existing = Asset.getBySerialNumber(serial);
                if (existing) {
                    results.skipped++;
                    continue;
                }

                // Map OS to asset type
                const os = (device.operatingSystem || '').toLowerCase();
                let type = 'Other';
                if (os.includes('windows') || os.includes('macos') || os.includes('mac os')) {
                    type = 'Notebook';
                }

                const name = device.deviceName || serial;
                const manufacturer = device.manufacturer || '';
                const model = device.model || '';
                const descParts = [`Quelle: Microsoft Intune`];
                if (manufacturer) descParts.push(`Hersteller: ${manufacturer}`);
                if (device.operatingSystem) descParts.push(`OS: ${device.operatingSystem}`);
                if (device.managedDeviceOwnerType) descParts.push(`Typ: ${device.managedDeviceOwnerType}`);

                AssetService.createAsset({
                    name,
                    type,
                    serial_number: serial,
                    model: model || null,
                    status: 'verfuegbar',
                    description: descParts.join(' | '),
                }, req.user.id, req.ip);

                results.imported++;
            } catch (err) {
                results.errors.push({ device: device.deviceName || device.serialNumber, error: err.message });
            }
        }

        res.json({ status: 'success', data: results });
    });

    /**
     * Get all inspections for an asset
     * GET /api/assets/:id/inspections
     */
    static getInspections = asyncHandler(async (req, res) => {
        const AssetInspection = require('../models/AssetInspection');
        const items = AssetInspection.getByAsset(parseInt(req.params.id));
        res.json({ status: 'success', data: items });
    });

    /**
     * Create an inspection for an asset
     * POST /api/assets/:id/inspections
     */
    static createInspection = asyncHandler(async (req, res) => {
        const AssetInspection = require('../models/AssetInspection');
        const { inspection_date, result, notes, next_due_date } = req.body;
        if (!inspection_date || !result) {
            return res.status(400).json({ status: 'error', message: 'inspection_date und result sind Pflichtfelder' });
        }
        const item = AssetInspection.create({
            asset_id: parseInt(req.params.id),
            inspected_by_user_id: req.user.id,
            inspection_date, result, notes, next_due_date
        });
        // If next_due_date provided, also update the asset's next_maintenance_date
        if (next_due_date) {
            const Asset = require('../models/Asset');
            Asset.update(parseInt(req.params.id), { next_maintenance_date: next_due_date }, req.user.id);
        }
        res.status(201).json({ status: 'success', data: item });
    });

    /**
     * Generate printable label PDF for an asset
     * GET /api/assets/:id/label?copies=1&size=medium
     */
    static generateLabel = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const copies = Math.min(parseInt(req.query.copies) || 1, 100);
        const size = ['small', 'medium', 'large', 'ptouch12'].includes(req.query.size)
            ? req.query.size
            : 'medium';

        const asset = AssetService.getAssetById(parseInt(id));

        const pdfBuffer = await LabelService.generateAssetLabel(asset, copies, size);
        const filename = `label_${(asset.serial_number || asset.id).replace(/[^a-z0-9]/gi, '_')}.pdf`;

        res.set({
            'Content-Type': 'application/pdf',
            'Content-Disposition': `inline; filename="${filename}"`,
            'Content-Length': pdfBuffer.length,
        });
        res.send(pdfBuffer);
    });

    /**
     * POST /api/assets/:id/sync-agent
     * Holt aktuelle Daten vom letzten Agent-Checkin und schreibt sie ins Asset
     */
    static syncFromAgent = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const asset = AssetService.getAssetById(parseInt(id));
        const db = require('../config/database').getDatabase();
        const MonitoringAgent = require('../models/MonitoringAgent');

        const agent = MonitoringAgent.getByHostname(asset.name);
        if (!agent) {
            return res.status(404).json({ status: 'error', message: 'Kein Agent für dieses Asset gefunden. Hostname muss mit Asset-Name übereinstimmen.' });
        }

        const syncData = {
            os: agent.os_name || null,
            ip_address: agent.ip_address || null,
            last_agent_sync: new Date().toISOString(),
        };
        if (agent.hardware_serial) syncData.serial_number = agent.hardware_serial;

        // Hersteller aus Modell extrahieren falls noch nicht gesetzt
        if (!asset.manufacturer && asset.model) {
            const known = ['HP', 'Dell', 'Lenovo', 'Apple', 'Asus', 'Acer', 'Microsoft', 'Samsung', 'Toshiba', 'Fujitsu', 'Panasonic', 'Getac'];
            const upper = asset.model.toUpperCase();
            for (const b of known) {
                if (upper.startsWith(b.toUpperCase())) { syncData.manufacturer = b; break; }
            }
        }

        // Benutzer anhand last_user suchen
        if (agent.last_user) {
            const cleanUser = agent.last_user.replace(/^[^\\]+\\/, '');
            const userRow = db.prepare('SELECT id FROM users WHERE LOWER(username) = LOWER(?) AND is_active = 1').get(cleanUser);
            if (userRow) {
                syncData.assigned_to_user_id = userRow.id;
                syncData.status = 'zugewiesen';
            }
        }

        const updated = Asset.update(parseInt(id), syncData, req.user.id);
        res.json({ status: 'success', data: updated, synced_from: agent.hostname, last_checkin: agent.last_checkin });
    });
}

module.exports = AssetController;
