/**
 * Notification Rules Tests
 *
 * Tests the connection status change handler, which fires a connection
 * notification sound exactly once per reconnect cycle.
 *
 * What this module does:
 * - Tracks the previous connection status in module-level state
 * - Fires a notification only when transitioning from a non-connected
 *   state (disconnected/connecting) to "connected"
 * - Ignores the initial connection (null → connected) to avoid noisy
 *   notifications on app start
 * - Provides no-op handlers for tool execution and user messages
 *   (reserved for future notification rules)
 * - cleanupNotificationRules() resets tracking state on teardown
 */

import { describe, it, expect, vi, beforeEach } from "vitest";

const { mockNotifyConnection } = vi.hoisted(() => ({
  mockNotifyConnection: vi.fn(),
}));

vi.mock("./notificationManager", () => ({
  notificationManager: {
    notifyConnection: mockNotifyConnection,
  },
}));

import {
  handleConnectionStatusChange,
  handleToolExecution,
  handleNewUserMessage,
  initializeNotificationRules,
  cleanupNotificationRules,
} from "./rules";

// ---

describe("handleConnectionStatusChange", () => {
  beforeEach(() => {
    mockNotifyConnection.mockReset();
    cleanupNotificationRules(); // Reset module-level previousConnectionStatus to null
  });

  describe("initial connection (null → status)", () => {
    it("does not notify on first connection (null → connected)", () => {
      // previousConnectionStatus is null (falsy), so condition is not met
      handleConnectionStatusChange("connected");
      expect(mockNotifyConnection).not.toHaveBeenCalled();
    });

    it("does not notify when disconnecting from initial state (null → disconnected)", () => {
      handleConnectionStatusChange("disconnected");
      expect(mockNotifyConnection).not.toHaveBeenCalled();
    });

    it("does not notify when entering connecting from initial state (null → connecting)", () => {
      handleConnectionStatusChange("connecting");
      expect(mockNotifyConnection).not.toHaveBeenCalled();
    });
  });

  describe("reconnection (disconnected → connected)", () => {
    it("notifies when reconnecting after a disconnection", () => {
      handleConnectionStatusChange("disconnected");
      handleConnectionStatusChange("connected");
      expect(mockNotifyConnection).toHaveBeenCalledWith();
    });

    it("notifies exactly once per reconnect", () => {
      handleConnectionStatusChange("disconnected");
      handleConnectionStatusChange("connected");
      expect(mockNotifyConnection).toHaveBeenCalledTimes(1);
    });
  });

  describe("reconnection (connecting → connected)", () => {
    it("notifies when transitioning from connecting to connected", () => {
      handleConnectionStatusChange("connecting");
      handleConnectionStatusChange("connected");
      expect(mockNotifyConnection).toHaveBeenCalledWith();
    });
  });

  describe("already connected (connected → connected)", () => {
    it("does not notify when already connected", () => {
      handleConnectionStatusChange("disconnected");
      handleConnectionStatusChange("connected"); // First connection — notifies
      mockNotifyConnection.mockReset();

      handleConnectionStatusChange("connected"); // Second — same status, no notify
      expect(mockNotifyConnection).not.toHaveBeenCalled();
    });
  });

  describe("disconnecting (connected → disconnected)", () => {
    it("does not notify when disconnecting", () => {
      handleConnectionStatusChange("disconnected");
      handleConnectionStatusChange("connected");
      mockNotifyConnection.mockReset();

      handleConnectionStatusChange("disconnected");
      expect(mockNotifyConnection).not.toHaveBeenCalled();
    });
  });

  describe("multiple reconnect cycles", () => {
    it("notifies once per reconnect cycle", () => {
      // First cycle
      handleConnectionStatusChange("disconnected");
      handleConnectionStatusChange("connected");
      expect(mockNotifyConnection).toHaveBeenCalledTimes(1);

      mockNotifyConnection.mockReset();

      // Second cycle
      handleConnectionStatusChange("disconnected");
      handleConnectionStatusChange("connected");
      expect(mockNotifyConnection).toHaveBeenCalledTimes(1);
    });
  });
});

describe("cleanupNotificationRules", () => {
  it("resets state so the next connection is treated as the first", () => {
    // Establish a known previous status
    handleConnectionStatusChange("disconnected");
    // Now cleanup
    cleanupNotificationRules();
    // After cleanup, previousConnectionStatus is null again
    // So the next "connected" should NOT notify (treated as initial connection)
    handleConnectionStatusChange("connected");
    expect(mockNotifyConnection).not.toHaveBeenCalled();
  });
});

describe("no-op handlers", () => {
  it("handleToolExecution does not throw", () => {
    expect(() => handleToolExecution("Bash")).not.toThrow();
  });

  it("handleNewUserMessage does not throw", () => {
    expect(() => handleNewUserMessage()).not.toThrow();
  });

  it("initializeNotificationRules does not throw", () => {
    expect(() => initializeNotificationRules()).not.toThrow();
  });
});
