let receivedLength = 0;
let expectedLength = 0;
let root;
let draftHandle;
let accessHandle;

const Operation = Object.freeze({
    WriteHeader: 1,
    WriteChunks: 2,
    DeleteFiles: 3
});

onmessage = async function (event) {
    try {
        const { operation, arrayBuffer, fileName } = event.data;

        switch (operation) {
            case Operation.WriteHeader: {
                const dataView = new DataView(arrayBuffer);
                expectedLength = Number(dataView.getBigUint64(4, false));
                receivedLength = 0;

                // Create a new temporary file
                root = await navigator.storage.getDirectory();
                draftHandle = await root.getFileHandle(fileName, { create: true });
                accessHandle = await draftHandle.createSyncAccessHandle();

                // Inform that file handle is created
                const dataChunk = arrayBuffer.slice(12);
                receivedLength += dataChunk.byteLength;
                accessHandle.write(dataChunk, { at: 0 });
                const progress = 'got handle';
                postMessage({ type: 'progress', progress: progress });
                break;
            }
            case Operation.WriteChunks: {
                if (!accessHandle) {
                    throw new Error('accessHandle is undefined');
                }

                const dataChunk = arrayBuffer;
                accessHandle.write(dataChunk, { at: receivedLength });
                receivedLength += dataChunk.byteLength;

                if (receivedLength === expectedLength) {
                    accessHandle.flush();
                    accessHandle.close();

                    const fileBlob = await draftHandle.getFile();
                    const blob = new Blob([fileBlob], { type: 'application/octet-stream' });

                    postMessage({ type: 'result', blob: blob, fileName: fileName });
                }
                break;
            }
            case Operation.DeleteFiles: {
                for await (const [name, handle] of root.entries()) {
                    if (handle.kind === 'file') {
                        await root.removeEntry(name);
                    } else if (handle.kind === 'directory') {
                        await root.removeEntry(name, { recursive: true });
                    }
                }
                break;
            }
        }
    } catch (error) {
        postMessage({ error: error.message });
    }
};