import { mkdirSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import { randomUUID } from "node:crypto";
import { readJsonFileWithBackup, writeJsonFileAtomic } from "../state/persistence.js";
const DEFAULT_HOME = path.join(os.homedir(), ".nordrelay");
const MAX_EVENTS_PER_PEER = 500;
export class PeerRelayEventStore {
    filePath;
    constructor(home = process.env.NORDRELAY_HOME || DEFAULT_HOME) {
        this.filePath = path.join(home, "peer-relay-events.json");
    }
    append(peerId, events) {
        if (!events.length)
            return [];
        const receivedAt = new Date().toISOString();
        const envelopes = events.map((event) => ({
            peerId,
            id: randomUUID().replace(/-/g, "").slice(0, 16),
            receivedAt,
            event,
        }));
        this.mutate((payload) => {
            const retainedForOtherPeers = payload.events.filter((item) => item.peerId !== peerId);
            const retainedForPeer = payload.events.filter((item) => item.peerId === peerId).concat(envelopes).slice(-MAX_EVENTS_PER_PEER);
            payload.events = [...retainedForOtherPeers, ...retainedForPeer].sort((left, right) => Date.parse(left.receivedAt) - Date.parse(right.receivedAt));
        });
        return envelopes;
    }
    list(peerId, afterId) {
        const events = this.readPayload().events.filter((event) => event.peerId === peerId);
        if (!afterId)
            return events.slice(-MAX_EVENTS_PER_PEER);
        const index = events.findIndex((event) => event.id === afterId);
        return index >= 0 ? events.slice(index + 1) : events.slice(-100);
    }
    mutate(mutator) {
        const payload = this.readPayload();
        mutator(payload);
        mkdirSync(path.dirname(this.filePath), { recursive: true });
        writeJsonFileAtomic(this.filePath, payload);
    }
    readPayload() {
        const payload = readJsonFileWithBackup(this.filePath).value;
        if (!payload || payload.version !== 1 || !Array.isArray(payload.events)) {
            return { version: 1, events: [] };
        }
        return { version: 1, events: payload.events.filter(isEventEnvelope).slice(-MAX_EVENTS_PER_PEER * 20) };
    }
}
function isEventEnvelope(value) {
    if (!value || typeof value !== "object")
        return false;
    const record = value;
    return typeof record.peerId === "string" &&
        typeof record.id === "string" &&
        typeof record.receivedAt === "string" &&
        Boolean(record.event);
}
