const FidoKey = require('../models/FidoKey');
const AuditLog = require('../models/AuditLog');
const { AppError } = require('../middleware/errorHandler');

class FidoKeyService {
    static getAllKeys() {
        return FidoKey.getAll();
    }

    static getKeysByUser(userId) {
        return FidoKey.getByAssignedUser(userId);
    }

    /**
     * Get FIDO key by ID
     */
    static getKeyById(id) {
        const key = FidoKey.getById(id);

        if (!key) {
            throw new AppError('FIDO key not found', 404);
        }

        return key;
    }

    /**
     * Get FIDO key by serial number
     */
    static getKeyBySerial(serialNumber) {
        const key = FidoKey.getBySerialNumber(serialNumber);

        if (!key) {
            throw new AppError('FIDO key not found', 404);
        }

        return key;
    }

    /**
     * Get FIDO keys by status
     */
    static getKeysByStatus(status) {
        // Validate status
        if (!['aktiv', 'inaktiv'].includes(status)) {
            throw new AppError('Invalid status. Must be "aktiv" or "inaktiv"', 400);
        }

        return FidoKey.getByStatus(status);
    }

    /**
     * Create new FIDO key
     */
    static createKey(keyData, createdByUserId, ipAddress) {
        // Validate required fields
        if (!keyData.name || !keyData.serial_number || !keyData.status) {
            throw new AppError('Missing required fields (name, serial_number, status)', 400);
        }

        // Validate status
        if (!['aktiv', 'inaktiv'].includes(keyData.status)) {
            throw new AppError('Invalid status. Must be "aktiv" or "inaktiv"', 400);
        }

        // Check if serial number already exists
        const existingKey = FidoKey.getBySerialNumber(keyData.serial_number);
        if (existingKey) {
            throw new AppError('Serial number already exists', 409);
        }

        // Create key
        const newKey = FidoKey.create({
            name: keyData.name,
            serial_number: keyData.serial_number,
            status: keyData.status,
            description: keyData.description,
            assigned_to_user_id: keyData.assigned_to_user_id,
            created_by_user_id: createdByUserId
        });

        // Log action
        AuditLog.logUserAction(
            createdByUserId,
            'CREATE_FIDO_KEY',
            'fido_key',
            newKey.id,
            null,
            { name: newKey.name, serial_number: newKey.serial_number },
            ipAddress
        );

        return newKey;
    }

    /**
     * Update FIDO key
     */
    static updateKey(id, keyData, updatedByUserId, ipAddress) {
        // Get existing key
        const existingKey = FidoKey.getById(id);
        if (!existingKey) {
            throw new AppError('FIDO key not found', 404);
        }

        // Validate status if being changed
        if (keyData.status && !['aktiv', 'inaktiv'].includes(keyData.status)) {
            throw new AppError('Invalid status. Must be "aktiv" or "inaktiv"', 400);
        }

        // Check if serial number is being changed and already exists
        if (keyData.serial_number && keyData.serial_number !== existingKey.serial_number) {
            const keyWithSerial = FidoKey.getBySerialNumber(keyData.serial_number);
            if (keyWithSerial) {
                throw new AppError('Serial number already exists', 409);
            }
        }

        // Update key
        const updatedKey = FidoKey.update(id, keyData, updatedByUserId);

        // Log action
        AuditLog.logUserAction(
            updatedByUserId,
            'UPDATE_FIDO_KEY',
            'fido_key',
            id,
            {
                name: existingKey.name,
                serial_number: existingKey.serial_number,
                status: existingKey.status
            },
            {
                name: updatedKey.name,
                serial_number: updatedKey.serial_number,
                status: updatedKey.status
            },
            ipAddress
        );

        return updatedKey;
    }

    /**
     * Update FIDO key status
     */
    static updateKeyStatus(id, status, updatedByUserId, ipAddress) {
        // Validate status
        if (!['aktiv', 'inaktiv'].includes(status)) {
            throw new AppError('Invalid status. Must be "aktiv" or "inaktiv"', 400);
        }

        // Get existing key
        const existingKey = FidoKey.getById(id);
        if (!existingKey) {
            throw new AppError('FIDO key not found', 404);
        }

        // Update status
        const updatedKey = FidoKey.updateStatus(id, status, updatedByUserId);

        // Log action
        AuditLog.logUserAction(
            updatedByUserId,
            'UPDATE_FIDO_KEY_STATUS',
            'fido_key',
            id,
            { status: existingKey.status },
            { status: status },
            ipAddress
        );

        return updatedKey;
    }

    /**
     * Delete FIDO key
     */
    static deleteKey(id, deletedByUserId, ipAddress) {
        // Get existing key
        const existingKey = FidoKey.getById(id);
        if (!existingKey) {
            throw new AppError('FIDO key not found', 404);
        }

        // Delete key
        const deleted = FidoKey.delete(id);

        if (deleted) {
            // Log action
            AuditLog.logUserAction(
                deletedByUserId,
                'DELETE_FIDO_KEY',
                'fido_key',
                id,
                {
                    name: existingKey.name,
                    serial_number: existingKey.serial_number
                },
                null,
                ipAddress
            );
        }

        return deleted;
    }

    /**
     * Get statistics
     */
    static getStatistics() {
        return FidoKey.getStatistics();
    }
}

module.exports = FidoKeyService;
