import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createTestPluginApi } from "../../test/helpers/plugins/plugin-api.js";

const listDevicePairingMock = vi.hoisted(() => vi.fn(async () => ({ pending: [] })));

vi.mock("./api.js", () => ({
  listDevicePairing: listDevicePairingMock,
}));

import { handleNotifyCommand } from "./notify.js";

describe("device-pair notify persistence", () => {
  let stateDir: string;

  beforeEach(async () => {
    vi.clearAllMocks();
    listDevicePairingMock.mockResolvedValue({ pending: [] });
    stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "device-pair-notify-"));
  });

  afterEach(async () => {
    await fs.rm(stateDir, { recursive: true, force: true });
  });

  it("matches persisted telegram thread ids across number and string roundtrips", async () => {
    await fs.writeFile(
      path.join(stateDir, "device-pair-notify.json"),
      JSON.stringify(
        {
          subscribers: [
            {
              to: "chat-123",
              accountId: "telegram-default",
              messageThreadId: 271,
              mode: "persistent",
              addedAtMs: 1,
            },
          ],
          notifiedRequestIds: {},
        },
        null,
        2,
      ),
      "utf8",
    );

    const api = createTestPluginApi({
      runtime: {
        state: {
          resolveStateDir: () => stateDir,
        },
      } as never,
    });

    const status = await handleNotifyCommand({
      api,
      ctx: {
        channel: "telegram",
        senderId: "chat-123",
        accountId: "telegram-default",
        messageThreadId: "271",
      },
      action: "status",
    });

    expect(status.text).toContain("Pair request notifications: enabled for this chat.");
    expect(status.text).toContain("Mode: persistent");

    await handleNotifyCommand({
      api,
      ctx: {
        channel: "telegram",
        senderId: "chat-123",
        accountId: "telegram-default",
        messageThreadId: "271",
      },
      action: "off",
    });

    const persisted = JSON.parse(
      await fs.readFile(path.join(stateDir, "device-pair-notify.json"), "utf8"),
    ) as { subscribers: unknown[] };
    expect(persisted.subscribers).toEqual([]);
  });

  it("does not remove a different persisted subscriber when notify fields contain pipes", async () => {
    await fs.writeFile(
      path.join(stateDir, "device-pair-notify.json"),
      JSON.stringify(
        {
          subscribers: [
            {
              to: "chat|123",
              accountId: "acct",
              mode: "persistent",
              addedAtMs: 1,
            },
            {
              to: "chat",
              accountId: "123|acct",
              mode: "persistent",
              addedAtMs: 2,
            },
          ],
          notifiedRequestIds: {},
        },
        null,
        2,
      ),
      "utf8",
    );

    const api = createTestPluginApi({
      runtime: {
        state: {
          resolveStateDir: () => stateDir,
        },
      } as never,
    });

    await handleNotifyCommand({
      api,
      ctx: {
        channel: "telegram",
        senderId: "chat",
        accountId: "123|acct",
      },
      action: "off",
    });

    const status = await handleNotifyCommand({
      api,
      ctx: {
        channel: "telegram",
        senderId: "chat",
        accountId: "123|acct",
      },
      action: "status",
    });
    expect(status.text).toContain("Pair request notifications: disabled for this chat.");

    const persisted = JSON.parse(
      await fs.readFile(path.join(stateDir, "device-pair-notify.json"), "utf8"),
    ) as { subscribers: Array<{ to: string; accountId?: string }> };
    expect(persisted.subscribers).toHaveLength(1);
    expect(persisted.subscribers[0]).toMatchObject({
      to: "chat|123",
      accountId: "acct",
    });
  });
});
