import { inspect } from 'node:util';
import picocolors from 'picocolors';
import { debug, resultToObject, readAllFields } from './query.js';
import { size, time, inspectData, defHasId, displayTarget } from './display.js';
import { readFloatLE, readUint32 } from '@saulx/utils';
export { time, size, inspectData };
const BITS_FOR_BYTE_LEN = 21;
const FACTOR = 2 ** BITS_FOR_BYTE_LEN;
const MASK_B = FACTOR - 1;
export class BasedQueryResponse {
    result;
    def;
    execTime;
    end;
    id;
    constructor(id, def, result, execTime, end = result.length) {
        this.id = id;
        this.def = def;
        this.result = result;
        this.execTime = execTime;
        this.end = end;
    }
    get version() {
        return (this.checksum >>> 0) * FACTOR + (this.result.byteLength & MASK_B);
    }
    get size() {
        return this.result.length;
    }
    [inspect.custom](depth) {
        const hasId = defHasId(this.def);
        const target = displayTarget(this.def);
        let str = '';
        str += '\n  execTime: ' + time(this.execTime);
        str += '\n  size: ' + size(this.result.byteLength);
        const dataStr = inspectData(this, this.def, 0, true, hasId && depth == 2 ? 5 : depth, hasId);
        str += '\n';
        str += dataStr;
        return `${picocolors.bold(`BasedQueryResponse[${target}]`)} {${str}\n}\n`;
    }
    debug() {
        debug(this.result, 0, this.end);
        return this;
    }
    node(index = 0) {
        // get id as well
        // and potentialy a proxy [i] as well
        let i = 0;
        if ('id' in this.def.target || 'alias' in this.def.target) {
            return this.toObject();
        }
        if (index < 0) {
            index = this.length + index;
        }
        for (const x of this) {
            if (i === index) {
                return x;
            }
            i++;
        }
        return null;
    }
    *[Symbol.iterator]() {
        let i = 5;
        const result = this.result;
        while (i < result.byteLength - 4) {
            let id = readUint32(result, i);
            i += 4;
            let item = {
                id,
            };
            if (this.def.search) {
                item.$searchScore = readFloatLE(result, i);
                i += 4;
            }
            const l = readAllFields(this.def, result, i, result.byteLength - 4, item, id);
            i += l;
            yield item;
        }
    }
    inspect(depth = 2, raw) {
        if (raw) {
            console.dir(this.toObject(), { depth });
        }
        else {
            console.log(this[inspect.custom](depth));
        }
        return this;
    }
    forEach(fn) {
        let i = 0;
        for (const item of this) {
            fn(item, ++i);
        }
    }
    map(fn) {
        const arr = new Array(this.length);
        let i = 0;
        for (const item of this) {
            arr[i++] = fn(item, i);
        }
        return arr;
    }
    get checksum() {
        const result = this.result;
        const offset = result.byteLength - 4;
        return readUint32(result, offset);
    }
    get length() {
        const l = readUint32(this.result, 0);
        return l;
    }
    toObject() {
        return resultToObject(this.def, this.result, this.end - 4, 0);
    }
    toJSON() {
        // TODO: optimize
        return JSON.stringify(this.toObject());
    }
    toString() {
        return this.toJSON();
    }
}
//# sourceMappingURL=BasedIterable.js.map