var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { dbResultToDtoList, jsonifyFields, removeUndefinedFields, transformListToDbEntity, transformToDbEntity, } from '../../../../CozoDb/utils';
import { extractSenseChats } from '../../sync/services/utils/sense';
import { MSG_MULTI_SEND_TRANSACTION_TYPE, MSG_SEND_TRANSACTION_TYPE, } from '../blockchain/types';
const TIMESTAMP_INTITAL = 0;
class DbApiWrapper {
    init(dbApi) {
        this.db = dbApi;
    }
    getSyncStatus(ownerId, id) {
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.db.executeGetCommand('sync_status', ['timestamp_update', 'unread_count', 'timestamp_read'], [`id = '${id}'`, `owner_id = '${ownerId}'`], ['id', 'owner_id']);
            if (!result.ok) {
                throw new Error(result === null || result === void 0 ? void 0 : result.message);
            }
            const row = result.rows.length
                ? result.rows[0]
                : [TIMESTAMP_INTITAL, 0, TIMESTAMP_INTITAL];
            return {
                timestampUpdate: row[0],
                unreadCount: row[1],
                timestampRead: row[2],
            };
        });
    }
    putSyncStatus(entity) {
        return __awaiter(this, void 0, void 0, function* () {
            const entitites = transformListToDbEntity(Array.isArray(entity) ? entity : [entity]);
            const result = yield this.db.executePutCommand('sync_status', entitites);
            return result;
        });
    }
    updateSyncStatus(entity) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.db.executeUpdateCommand('sync_status', [
                transformToDbEntity(removeUndefinedFields(entity)),
            ]);
        });
    }
    findSyncStatus({ ownerId, entryType, id, }) {
        return __awaiter(this, void 0, void 0, function* () {
            const conditions = [`owner_id = '${ownerId}'`];
            entryType && conditions.push(`entry_type = ${entryType}`);
            id && conditions.push(`id = '${id}'`);
            const result = yield this.db.executeGetCommand('sync_status', ['id', 'unread_count', 'timestamp_update', 'timestamp_read'], conditions, ['entry_type']);
            return dbResultToDtoList(result);
        });
    }
    putTransactions(transactions) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.db.executePutCommand('transaction', transactions);
        });
    }
    putPins(pins) {
        return __awaiter(this, void 0, void 0, function* () {
            const entitites = Array.isArray(pins) ? pins : [pins];
            return this.db.executePutCommand('pin', entitites);
        });
    }
    getPins(withType = false) {
        return __awaiter(this, void 0, void 0, function* () {
            const fields = withType ? ['cid', 'type'] : ['cid'];
            const result = yield this.db.executeGetCommand('pin', fields);
            if (!result.ok) {
                throw new Error(result === null || result === void 0 ? void 0 : result.message);
            }
            return result;
        });
    }
    deletePins(pins) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.db.executeRmCommand('pin', pins.map((cid) => ({ cid })));
        });
    }
    putParticles(particles) {
        return __awaiter(this, void 0, void 0, function* () {
            const entitites = transformListToDbEntity(Array.isArray(particles) ? particles : [particles]);
            yield this.db.executePutCommand('particle', entitites);
        });
    }
    getParticles(fields) {
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.db.executeGetCommand('particle', fields);
            if (!result.ok) {
                throw new Error(result === null || result === void 0 ? void 0 : result.message);
            }
            return result;
        });
    }
    getSenseList(myAddress = '') {
        return __awaiter(this, void 0, void 0, function* () {
            const command = `
    ss_p[last_id, id, meta] := *sync_status{entry_type,id, last_id, meta}, entry_type=2, owner_id = '${myAddress}'

    p_last[last_id, id, meta, text, mime] := ss_p[last_id, id, meta], *particle{cid: last_id, text, mime}
    p_last[last_id, id, meta, empty, empty] := ss_p[last_id, id, meta], not *particle{cid: last_id, text, mime}, empty=''

    p_id[last_id, id, meta, text, mime] :=  ss_p[last_id, id, meta], *particle{cid: id, text, mime}
    p_id[last_id, id, meta, empty, empty] := ss_p[last_id, id, meta], not *particle{cid: id, text, mime}, empty=''

    p_last_m[last_id, id, m] :=  p_last[last_id, id, meta, text, mime], m= concat(meta, json_object('last_id', json_object('text', text, 'mime', mime)))

    p_join[last_id, id, m] :=  p_id[last_id, id, meta, text, mime], p_last_m[last_id, id, meta_prev], m= concat(meta, meta_prev, json_object('id', json_object('text', text, 'mime', mime)))

    ss_t[last_id, id, m] := *sync_status{entry_type,id, last_id, meta}, entry_type=1, *transaction{hash: last_id, value, type}, m= concat(meta, json_object('value', value, 'type', type)), id!='${myAddress}', owner_id = '${myAddress}'
    ?[entry_type, id, unread_count, timestamp_update, timestamp_read, last_id, meta] := *sync_status{entry_type, id, unread_count, timestamp_update, timestamp_read, last_id, meta}, entry_type=3, owner_id = '${myAddress}'
    ?[entry_type, id, unread_count, timestamp_update, timestamp_read, last_id, meta] := *sync_status{entry_type, id, unread_count, timestamp_update, timestamp_read, last_id}, p_join[last_id, id, meta] or ss_t[last_id, id, meta]
    :order -timestamp_update
    `;
            const result = yield this.db.runCommand(command);
            return dbResultToDtoList(result).map((i) => jsonifyFields(i, ['meta']));
        });
    }
    getSenseSummary(myAddress = '') {
        return __awaiter(this, void 0, void 0, function* () {
            const command = `?[entry_type, sum(unread_count)] := *sync_status{id, entry_type, unread_count}, id!='${myAddress}'`;
            const result = yield this.db.runCommand(command);
            return dbResultToDtoList(result);
        });
    }
    senseMarkAsRead(ownerId, id) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.db.executeGetCommand('sync_status', ['timestamp_update'], [`id = '${id}'`, `owner_id = '${ownerId}'`], ['id', 'owner_id']);
            const timestampUpdate = (_a = result === null || result === void 0 ? void 0 : result.rows) === null || _a === void 0 ? void 0 : _a[0];
            this.updateSyncStatus({
                id,
                ownerId,
                timestampUpdate,
                timestampRead: timestampUpdate,
                unreadCount: 0,
            });
        });
    }
    getTransactions(neuron, order = 'desc') {
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.db.executeGetCommand('transaction', ['hash', 'type', 'success', 'value', 'timestamp', 'memo'], [`neuron = '${neuron}'`], ['neuron'], { orderBy: [order === 'desc' ? '-timestamp' : 'timestamp'] });
            return dbResultToDtoList(result).map((i) => jsonifyFields(i, ['value']));
        });
    }
    getMyChats(myAddress, userAddress) {
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.db.executeGetCommand('transaction', ['hash', 'type', 'success', 'value', 'timestamp', 'memo'], [
                `neuron = '${myAddress}', type='${MSG_SEND_TRANSACTION_TYPE}' or type='${MSG_MULTI_SEND_TRANSACTION_TYPE}'`,
            ], ['neuron'], { orderBy: ['-timestamp'] });
            const sendTransactions = dbResultToDtoList(result).map((i) => jsonifyFields(i, ['value']));
            const chats = extractSenseChats(myAddress, sendTransactions);
            const userChats = [...chats.values()].find((c) => c.userAddress === userAddress);
            return userChats ? userChats.transactions : [];
        });
    }
    putCyberlinks(links) {
        return __awaiter(this, void 0, void 0, function* () {
            const entitites = Array.isArray(links) ? links : [links];
            return this.db.executePutCommand('link', entitites);
        });
    }
    putSyncQueue(item) {
        return __awaiter(this, void 0, void 0, function* () {
            const entitites = Array.isArray(item) ? item : [item];
            return this.db.executePutCommand('sync_queue', entitites);
        });
    }
    updateSyncQueue(item) {
        return __awaiter(this, void 0, void 0, function* () {
            const entitites = Array.isArray(item) ? item : [item];
            return this.db.executeUpdateCommand('sync_queue', entitites);
        });
    }
    removeSyncQueue(id) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.db.executeRmCommand('sync_queue', [{ id }]);
        });
    }
    getSyncQueue({ statuses, limit, }) {
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.db.executeGetCommand('sync_queue', ['id', 'status', 'priority'], [`status in [${statuses.join(',')}]`], [], { orderBy: ['-priority'], limit });
            if (!result.ok) {
                throw new Error(result === null || result === void 0 ? void 0 : result.message);
            }
            return result.rows.map((row) => ({
                id: row[0],
                status: row[1],
                priority: row[2],
            }));
        });
    }
    getLinks(cid) {
        return __awaiter(this, void 0, void 0, function* () {
            const fields = [
                'mime',
                'text',
                'from',
                'to',
                'direction',
                'timestamp',
            ].join(', ');
            const command = `
    pf[${fields}] := *link{from, to,timestamp}, *particle{cid: from, text, mime}, direction='from'
    pf[${fields}] := *link{from, to,timestamp}, *particle{cid: to, text, mime}, direction='to'
    ?[${fields}] := pf[${fields}], from='${cid}' or to='${cid}'
    :order -timestamp`;
            const result = yield this.db.runCommand(command);
            return dbResultToDtoList(result);
        });
    }
}
export default DbApiWrapper;
//# sourceMappingURL=dbApiWrapper.js.map