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 OnboardingService {
    static getAllProtocols() {
        return OnboardingProtocol.getAll();
    }

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

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

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

        // Check if linked system user exists (optional for new hires)
        if (protocolData.employee_user_id) {
            const employee = User.getById(protocolData.employee_user_id);
            if (!employee) {
                throw new AppError('Mitarbeiter nicht gefunden', 404);
            }
        }

        // Create protocol
        const protocol = OnboardingProtocol.create({
            employee_user_id: protocolData.employee_user_id || null,
            emp_first_name: protocolData.emp_first_name,
            emp_last_name: protocolData.emp_last_name,
            emp_private_email: protocolData.emp_private_email,
            emp_phone: protocolData.emp_phone,
            emp_address: protocolData.emp_address,
            department: protocolData.department,
            position: protocolData.position,
            work_location: protocolData.work_location,
            hours_model: protocolData.hours_model,
            vacation_model: protocolData.vacation_model,
            dept_contacts: protocolData.dept_contacts ? JSON.stringify(protocolData.dept_contacts) : null,
            status: protocolData.status,
            start_date: protocolData.start_date,
            checklist_data: protocolData.checklist_data ? JSON.stringify(protocolData.checklist_data) : null,
            notes: protocolData.notes,
            created_by_user_id: createdByUserId
        });

        // Assign assets if provided
        if (protocolData.asset_ids && protocolData.asset_ids.length > 0) {
            for (const assetId of protocolData.asset_ids) {
                try {
                    await AssetAssignment.create({
                        asset_id: assetId,
                        user_id: protocolData.employee_user_id,
                        assigned_by_user_id: createdByUserId,
                        onboarding_protocol_id: protocol.id
                    });

                    Asset.update(assetId, {
                        status: 'zugewiesen',
                        assigned_to_user_id: protocolData.employee_user_id
                    }, createdByUserId);
                } catch (error) {
                    console.error(`Failed to assign asset ${assetId}:`, error);
                }
            }
        }

        // Generate PDF
        try {
            const assignedAssets = protocolData.employee_user_id
                ? AssetAssignment.getActiveAssignmentsByUser(protocolData.employee_user_id).map(a => Asset.getById(a.asset_id))
                : [];
            const createdBy = User.getById(createdByUserId);
            // Use system user if linked, otherwise build a pseudo-employee from wizard fields
            const employee = protocolData.employee_user_id ? User.getById(protocolData.employee_user_id) : null;
            const employeeForPdf = employee || {
                first_name: protocol.emp_first_name || '',
                last_name: protocol.emp_last_name || '',
                username: protocol.emp_private_email || '—',
                email: protocol.emp_private_email || '—',
                role_name: protocol.position || '—',
            };

            const pdfPath = await PDFService.generateOnboardingPdf(
                protocol,
                employeeForPdf,
                assignedAssets,
                createdBy.username
            );

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

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

        return OnboardingProtocol.getById(protocol.id);
    }

    static async updateProtocol(id, protocolData, updatedByUserId, ipAddress) {
        const existingProtocol = OnboardingProtocol.getById(id);
        if (!existingProtocol) {
            throw new AppError('Onboarding-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);
        }
        if (protocolData.dept_contacts) {
            updateData.dept_contacts = JSON.stringify(protocolData.dept_contacts);
        }

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

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

        return updatedProtocol;
    }

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

        const employee = protocol.employee_user_id ? User.getById(protocol.employee_user_id) : null;
        const assignedAssets = protocol.employee_user_id
            ? AssetAssignment.getActiveAssignmentsByUser(protocol.employee_user_id).map(a => Asset.getById(a.asset_id))
            : [];
        const createdBy = User.getById(regeneratedByUserId);
        const employeeForPdf = employee || {
            first_name: protocol.emp_first_name || '',
            last_name: protocol.emp_last_name || '',
            username: protocol.emp_private_email || '—',
            email: protocol.emp_private_email || '—',
            role_name: protocol.position || '—',
        };

        const pdfPath = await PDFService.generateOnboardingPdf(
            protocol,
            employeeForPdf,
            assignedAssets,
            createdBy.username
        );

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

        return OnboardingProtocol.getById(protocol.id);
    }

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

        const deleted = OnboardingProtocol.delete(id);

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

        return deleted;
    }

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

module.exports = OnboardingService;
