import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
import { join } from "node:path";

export function createThreadPreferencesStore(dataDir) {
  const filePath = dataDir ? join(dataDir, "thread-preferences.json") : "";
  const temporaryPath = dataDir ? join(dataDir, "thread-preferences.json.tmp") : "";
  async function load() {
    if (!filePath) return { pinned: [], deleted: [] };
    try {
      const value = JSON.parse(await readFile(filePath, "utf8"));
      return {
        pinned: Array.isArray(value.pinned) ? value.pinned.filter(isThreadRef) : [],
        deleted: Array.isArray(value.deleted) ? value.deleted.filter(isThreadRef) : []
      };
    } catch (error) {
      if (error.code === "ENOENT") return { pinned: [], deleted: [] };
      throw error;
    }
  }
  async function save(state) {
    if (!filePath) return;
    await mkdir(dataDir, { recursive: true });
    await writeFile(temporaryPath, JSON.stringify(state, null, 2), "utf8");
    await rename(temporaryPath, filePath);
  }
  return {
    async isPinned(ownerId, threadId) {
      return (await load()).pinned.some((item) => item.ownerId === ownerId && item.threadId === threadId);
    },
    async pinnedKeys() {
      return new Set((await load()).pinned.map((item) => `${item.ownerId}:${item.threadId}`));
    },
    async deletedKeys() {
      return new Set((await load()).deleted.map((item) => `${item.ownerId}:${item.threadId}`));
    },
    async setPinned(ownerId, threadId, pinned) {
      if (!filePath) return;
      const state = await load();
      state.pinned = state.pinned.filter((item) => item.ownerId !== ownerId || item.threadId !== threadId);
      if (pinned) state.pinned.push({ ownerId, threadId });
      await save(state);
    },
    async setDeleted(ownerId, threadId, deleted) {
      if (!filePath) return;
      const state = await load();
      state.deleted = state.deleted.filter((item) => item.ownerId !== ownerId || item.threadId !== threadId);
      state.pinned = state.pinned.filter((item) => item.ownerId !== ownerId || item.threadId !== threadId);
      if (deleted) state.deleted.push({ ownerId, threadId });
      await save(state);
    }
  };
}

function isThreadRef(value) {
  return value && typeof value.ownerId === "string" && typeof value.threadId === "string";
}
