import { createRequire } from 'node:module';
import { dirname } from 'node:path';
import { Transform } from 'node:stream';
import { TransformStream } from 'node:stream/web';
import { MAX_SIZE } from './config.js';
import { coercionInput, checkLevel } from './utils.js';
import { createModule, createZSTD_VERSION } from './common.js';
const nodeRequire = createRequire(import.meta.url);
const rootDir = dirname(nodeRequire.resolve('#packageJson'));
const bindings = nodeRequire('node-gyp-build')(rootDir);
/** NodeJs Transform stream Compressor/Decompressor */
class CompressTransform extends Transform {
    constructor(_type) {
        super({ objectMode: false });
        this._type = _type;
        this._binding = null;
    }
    /** @inheritdoc */
    _construct(callback) {
        try {
            this._binding = this.binding();
            callback();
        }
        catch (ex) {
            callback(ex);
        }
    }
    /** @inheritdoc */
    _transform(chunk, encoding, callback) {
        try {
            if (this._binding == null)
                throw new Error(`${this._type} is destroyed`);
            this._binding.data(coercionInput(chunk, false), (data) => this.push(data));
            callback();
        }
        catch (ex) {
            callback(ex);
        }
    }
    /** @inheritdoc */
    _flush(callback) {
        try {
            if (this._binding == null)
                throw new Error(`${this._type} is destroyed`);
            this._binding.end((data) => this.push(data));
            callback();
        }
        catch (ex) {
            callback(ex);
        }
    }
    /** @inheritdoc */
    _destroy(error, callback) {
        try {
            this._binding = null;
            callback(error);
        }
        catch (ex) {
            callback(ex);
        }
    }
}
/** NodeJs Transform stream Compressor */
export class Compressor extends CompressTransform {
    constructor(level) {
        super('Compressor');
        this._level = checkLevel(level);
    }
    /** @inheritdoc */
    binding() {
        return new bindings.Compressor(this._level);
    }
}
/** NodeJs Transform stream Decompressor */
export class Decompressor extends CompressTransform {
    constructor() {
        super('Decompressor');
    }
    /** @inheritdoc */
    binding() {
        return new bindings.Decompressor();
    }
}
/** Web Transform stream Compressor/Decompressor */
class WebCompressTransformer {
    constructor() {
        this._binding = null;
    }
    /** @inheritdoc */
    transform(chunk, controller) {
        try {
            this._binding.data(coercionInput(chunk, false), (data) => controller.enqueue(asUint8Array(data)));
        }
        catch (ex) {
            controller.error(ex);
            this._binding = null;
        }
    }
    /** @inheritdoc */
    flush(controller) {
        try {
            this._binding.end((data) => controller.enqueue(asUint8Array(data)));
        }
        catch (ex) {
            controller.error(ex);
        }
        finally {
            this._binding = null;
        }
    }
}
/** Stream compressor */
export class WebCompressor extends WebCompressTransformer {
    constructor(level) {
        super();
        this.level = level;
    }
    /** @inheritdoc */
    start(controller) {
        this._binding = new bindings.Compressor(this.level);
    }
}
/** Stream decompressor */
export class WebDecompressor extends WebCompressTransformer {
    /** @inheritdoc */
    start(controller) {
        this._binding = new bindings.Decompressor();
    }
}
/** Convert to Uint8Array */
function asUint8Array(buf) {
    return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
}
export const { compressSync, compress, decompressSync, decompress, compressor, decompressor } = createModule({
    compressSync: (data, level) => asUint8Array(bindings.compress(data, level)),
    decompressSync: (data) => asUint8Array(bindings.decompress(data, MAX_SIZE)),
    compress: async (data, level) => {
        const bin = ArrayBuffer.isView(data) ? data : new Uint8Array(await data.arrayBuffer());
        return new Promise((resolve, reject) => {
            bindings.compress_async(bin, level, (error, data) => {
                if (error)
                    reject(new Error(error));
                else
                    resolve(asUint8Array(data));
            });
        });
    },
    decompress: async (data) => {
        const bin = ArrayBuffer.isView(data) ? data : new Uint8Array(await data.arrayBuffer());
        return new Promise((resolve, reject) => {
            bindings.decompress_async(bin, MAX_SIZE, (error, data) => {
                if (error)
                    reject(new Error(error));
                else
                    resolve(asUint8Array(data));
            });
        });
    },
    Compressor: WebCompressor,
    Decompressor: WebDecompressor,
    TransformStream: TransformStream,
});
export const ZSTD_VERSION = createZSTD_VERSION(() => bindings.version);
export const TYPE = 'napi';
// For testing purpose
export const _NapiBindings = bindings;
export default null;
//# sourceMappingURL=napi.js.map