const OffboardingProtocol = require('../models/OffboardingProtocol');
const OnboardingProtocol = require('../models/OnboardingProtocol');
const Asset = require('../models/Asset');
const AssetAssignment = require('../models/AssetAssignment');
const User = require('../models/User');
const AuditLog = require('../models/AuditLog');
const PDFService = require('./pdf.service');
const { AppError } = require('../middleware/errorHandler');

const VALID_STATUSES = ['pending', 'in_progress', 'completed'];

class OffboardingService {
    static getAllProtocols() {
        return OffboardingProtocol.getAll();
    }

    static getProtocolById(id) {
        const protocol = OffboardingProtocol.getById(id);
        if (!protocol) {
            throw new AppError('Offboarding-Protokoll nicht gefunden', 404);
        }
        return protocol;
    }

    static async createProtocol(protocolData, createdByUserId, ipAddress) {
        if (!protocolData.employee_user_id || !protocolData.exit_date || !protocolData.status) {
            throw new AppError('Fehlende Pflichtfelder (employee_user_id, exit_date, status)', 400);
        }

        if (!VALID_STATUSES.includes(protocolData.status)) {
            throw new AppError(`Ungültiger Status. Muss einer sein von: ${VALID_STATUSES.join(', ')}`, 400);
        }

        const employee = User.getById(protocolData.employee_user_id);
        if (!employee) {
            throw new AppError('Mitarbeiter nicht gefunden', 404);
        }

        const protocol = OffboardingProtocol.create({
            employee_user_id: protocolData.employee_user_id,
            status: protocolData.status,
            exit_date: protocolData.exit_date,
            checklist_data: protocolData.checklist_data ? JSON.stringify(protocolData.checklist_data) : null,
            notes: protocolData.notes,
            created_by_user_id: createdByUserId
        });

        // Lösche automatisch das zugehörige Onboarding-Protokoll
        try {
            const onboardingProtocols = OnboardingProtocol.getByEmployee(protocolData.employee_user_id);
            if (onboardingProtocols && onboardingProtocols.length > 0) {
                for (const onboardingProtocol of onboardingProtocols) {
                    OnboardingProtocol.delete(onboardingProtocol.id);
                    AuditLog.logUserAction(
                        createdByUserId,
                        'DELETE_ONBOARDING_PROTOCOL_AUTO',
                        'onboarding_protocol',
                        onboardingProtocol.id,
                        { employee_user_id: onboardingProtocol.employee_user_id, reason: 'Offboarding erstellt' },
                        null,
                        ipAddress
                    );
                }
            }
        } catch (error) {
            console.error('Fehler beim Löschen des Onboarding-Protokolls:', error);
            // Nicht kritisch, Offboarding-Protokoll bleibt bestehen
        }

        AuditLog.logUserAction(
            createdByUserId,
            'CREATE_OFFBOARDING_PROTOCOL',
            'offboarding_protocol',
            protocol.id,
            null,
            { employee_user_id: protocol.employee_user_id },
            ipAddress
        );

        return OffboardingProtocol.getById(protocol.id);
    }

    static async updateProtocol(id, protocolData, updatedByUserId, ipAddress) {
        const existingProtocol = OffboardingProtocol.getById(id);
        if (!existingProtocol) {
            throw new AppError('Offboarding-Protokoll nicht gefunden', 404);
        }

        if (protocolData.status && !VALID_STATUSES.includes(protocolData.status)) {
            throw new AppError(`Ungültiger Status. Muss einer sein von: ${VALID_STATUSES.join(', ')}`, 400);
        }

        const updateData = { ...protocolData };
        if (protocolData.checklist_data) {
            updateData.checklist_data = JSON.stringify(protocolData.checklist_data);
        }

        const updatedProtocol = OffboardingProtocol.update(id, updateData, updatedByUserId);

        AuditLog.logUserAction(
            updatedByUserId,
            'UPDATE_OFFBOARDING_PROTOCOL',
            'offboarding_protocol',
            id,
            { status: existingProtocol.status },
            { status: updatedProtocol.status },
            ipAddress
        );

        return updatedProtocol;
    }

    static async returnAssets(protocolId, assetReturns, returnedByUserId, ipAddress) {
        const protocol = OffboardingProtocol.getById(protocolId);
        if (!protocol) {
            throw new AppError('Offboarding-Protokoll nicht gefunden', 404);
        }

        for (const assetReturn of assetReturns) {
            const assignment = AssetAssignment.getCurrentAssignment(assetReturn.asset_id);
            if (assignment && assignment.user_id === protocol.employee_user_id) {
                AssetAssignment.markAsReturned(assignment.id, protocolId);

                const newStatus = assetReturn.condition === 'beschaedigt' ? 'beschaedigt' : 'verfuegbar';
                Asset.update(assetReturn.asset_id, {
                    status: newStatus,
                    assigned_to_user_id: null
                }, returnedByUserId);
            }
        }

        // Generate PDF with returned assets
        try {
            const employee = User.getById(protocol.employee_user_id);
            const returnedAssets = assetReturns.map(ar => {
                const asset = Asset.getById(ar.asset_id);
                return { ...asset, condition: ar.condition || 'Gut' };
            });
            const createdBy = User.getById(returnedByUserId);

            const pdfPath = await PDFService.generateOffboardingPdf(
                protocol,
                employee,
                returnedAssets,
                createdBy.username
            );

            OffboardingProtocol.updatePdfPath(protocol.id, pdfPath, returnedByUserId);
        } catch (error) {
            console.error('PDF generation failed:', error);
        }

        return OffboardingProtocol.getById(protocolId);
    }

    static async regeneratePdf(id, regeneratedByUserId, ipAddress) {
        const protocol = OffboardingProtocol.getById(id);
        if (!protocol) {
            throw new AppError('Offboarding-Protokoll nicht gefunden', 404);
        }

        const employee = User.getById(protocol.employee_user_id);
        const assignments = AssetAssignment.getByUserId(protocol.employee_user_id)
            .filter(a => a.offboarding_protocol_id === protocol.id);
        const returnedAssets = assignments.map(a => Asset.getById(a.asset_id));
        const createdBy = User.getById(regeneratedByUserId);

        const pdfPath = await PDFService.generateOffboardingPdf(
            protocol,
            employee,
            returnedAssets,
            createdBy.username
        );

        OffboardingProtocol.updatePdfPath(protocol.id, pdfPath, regeneratedByUserId);

        return OffboardingProtocol.getById(protocol.id);
    }

    static deleteProtocol(id, deletedByUserId, ipAddress) {
        const protocol = OffboardingProtocol.getById(id);
        if (!protocol) {
            throw new AppError('Offboarding-Protokoll nicht gefunden', 404);
        }

        const deleted = OffboardingProtocol.delete(id);

        if (deleted) {
            AuditLog.logUserAction(
                deletedByUserId,
                'DELETE_OFFBOARDING_PROTOCOL',
                'offboarding_protocol',
                id,
                { employee_user_id: protocol.employee_user_id },
                null,
                ipAddress
            );
        }

        return deleted;
    }

    static getStatistics() {
        return OffboardingProtocol.getStatistics();
    }
}

module.exports = OffboardingService;
