import { dbGetText } from './sql.js';
import { nodeIdToBytes16, replicaIdToBytes } from '@treecrdt/interface/ids';
import { clearOpfsStorage } from './opfs.js';
export function openedToRpcInitResult(opened) {
    return opened.opfsError
        ? { storage: opened.storage, filename: opened.filename, opfsError: opened.opfsError }
        : { storage: opened.storage, filename: opened.filename };
}
/**
 * Shared wa-sqlite + TreeCRDT adapter state for dedicated or shared worker entrypoints.
 * Lifecycle (`init`, port `close`, `broadcastMaterialized`) stays in each worker file.
 */
export class CommonWorkerSession {
    constructor() {
        this.db = null;
        this.api = null;
        this.storedStorage = 'memory';
    }
    onAfterReset() { }
    applyOpened(opened) {
        this.db = opened.db;
        this.api = opened.api;
        this.storedFilename = opened.filename;
        this.storedStorage = opened.storage;
    }
    async closeDbAndReset() {
        if (this.db?.close)
            await this.db.close();
        this.db = null;
        this.api = null;
        this.storedFilename = undefined;
        this.storedStorage = 'memory';
        this.onAfterReset();
    }
    async drop() {
        const filename = this.storedFilename;
        const storage = this.storedStorage;
        await this.closeDbAndReset();
        if (storage === 'opfs' && filename) {
            await clearOpfsStorage(filename);
        }
        return null;
    }
    ensureApi() {
        if (!this.db || !this.api)
            throw new Error('db not initialized');
        return this.api;
    }
    ensureDb() {
        if (!this.db)
            throw new Error('db not initialized');
        return this.db;
    }
    async sqlExec(sql) {
        await this.ensureDb().exec(sql);
        return null;
    }
    async sqlGetText(sql, params) {
        return dbGetText(this.ensureDb(), sql, params ?? []);
    }
    async append(op) {
        return await this.ensureApi().appendOp(op, nodeIdToBytes16, replicaIdToBytes);
    }
    async appendMany(ops) {
        return await this.ensureApi().appendOps(ops, nodeIdToBytes16, replicaIdToBytes);
    }
    async opsSince(lamport, root) {
        return await this.ensureApi().opsSince(lamport, root);
    }
    async opRefsAll() {
        return await this.ensureApi().opRefsAll();
    }
    async opRefsChildren(parent) {
        return await this.ensureApi().opRefsChildren(nodeIdToBytes16(parent));
    }
    async opsByOpRefs(opRefs) {
        return await this.ensureApi().opsByOpRefs(opRefs.map((r) => Uint8Array.from(r)));
    }
    async treeChildren(parent) {
        return await this.ensureApi().treeChildren(nodeIdToBytes16(parent));
    }
    async treeChildrenPage(parent, cursor, limit) {
        const cursorBytes = cursor
            ? {
                orderKey: Uint8Array.from(cursor.orderKey),
                node: Uint8Array.from(cursor.node),
            }
            : null;
        return await this.ensureApi().treeChildrenPage(nodeIdToBytes16(parent), cursorBytes, limit);
    }
    async treeDump() {
        return await this.ensureApi().treeDump();
    }
    async treePayload(node) {
        const payload = await this.ensureApi().treePayload(nodeIdToBytes16(node));
        return payload === null ? null : Array.from(payload);
    }
    async treeNodeCount() {
        return await this.ensureApi().treeNodeCount();
    }
    async treeParent(node) {
        const result = await this.ensureApi().treeParent(nodeIdToBytes16(node));
        return result === null ? null : Array.from(result);
    }
    async treeExists(node) {
        return await this.ensureApi().treeExists(nodeIdToBytes16(node));
    }
    async headLamport() {
        return await this.ensureApi().headLamport();
    }
    async replicaMaxCounter(replica) {
        return await this.ensureApi().replicaMaxCounter(Uint8Array.from(replica));
    }
}
/** RPC methods shared by dedicated and shared workers (excluding lifecycle). */
export function createCommonWorkerRpcHandlers(session) {
    return {
        sqlExec: (sql) => session.sqlExec(sql),
        sqlGetText: (sql, params) => session.sqlGetText(sql, params),
        append: (op) => session.append(op),
        appendMany: (ops) => session.appendMany(ops),
        opsSince: (lamport, root) => session.opsSince(lamport, root),
        opRefsAll: () => session.opRefsAll(),
        opRefsChildren: (parent) => session.opRefsChildren(parent),
        opsByOpRefs: (opRefs) => session.opsByOpRefs(opRefs),
        treeChildren: (parent) => session.treeChildren(parent),
        treeChildrenPage: (parent, cursor, limit) => session.treeChildrenPage(parent, cursor, limit),
        treeDump: () => session.treeDump(),
        treeNodeCount: () => session.treeNodeCount(),
        treeParent: (node) => session.treeParent(node),
        treeExists: (node) => session.treeExists(node),
        treePayload: (node) => session.treePayload(node),
        headLamport: () => session.headLamport(),
        replicaMaxCounter: (replica) => session.replicaMaxCounter(replica),
    };
}
