import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { writable } from "svelte/store";

const mockSetEnabled = vi.fn();
const mockSetGlobalVolume = vi.fn();

vi.mock("$lib/notifications", () => ({
  soundPlayer: {
    setEnabled: mockSetEnabled,
    setGlobalVolume: mockSetGlobalVolume,
  },
}));

// We need to control the config store's emitted values
const configWritable = writable({
  notifications_enabled: true,
  notification_volume: 0.7,
});

vi.mock("./config", () => ({
  configStore: {
    config: { subscribe: configWritable.subscribe },
  },
}));

describe("notifications sync store", () => {
  beforeEach(async () => {
    vi.resetModules();
    mockSetEnabled.mockReset();
    mockSetGlobalVolume.mockReset();
    configWritable.set({ notifications_enabled: true, notification_volume: 0.7 });
  });

  afterEach(async () => {
    // Re-import to clean up any lingering subscriptions
    const { cleanupNotificationSync } = await import("./notifications");
    cleanupNotificationSync();
  });

  describe("initNotificationSync", () => {
    it("syncs soundPlayer enabled state from config on init", async () => {
      const { initNotificationSync } = await import("./notifications");
      initNotificationSync();
      expect(mockSetEnabled).toHaveBeenCalledWith(true);
    });

    it("syncs soundPlayer volume from config on init", async () => {
      const { initNotificationSync } = await import("./notifications");
      initNotificationSync();
      expect(mockSetGlobalVolume).toHaveBeenCalledWith(0.7);
    });

    it("updates soundPlayer when config changes", async () => {
      const { initNotificationSync } = await import("./notifications");
      initNotificationSync();

      mockSetEnabled.mockReset();
      mockSetGlobalVolume.mockReset();

      configWritable.set({ notifications_enabled: false, notification_volume: 0.3 });

      expect(mockSetEnabled).toHaveBeenCalledWith(false);
      expect(mockSetGlobalVolume).toHaveBeenCalledWith(0.3);
    });

    it("does not register a duplicate subscription when called twice", async () => {
      const { initNotificationSync } = await import("./notifications");
      initNotificationSync();
      initNotificationSync();

      // Both calls should only produce one subscription (one initial sync)
      expect(mockSetEnabled).toHaveBeenCalledTimes(1);
    });
  });

  describe("cleanupNotificationSync", () => {
    it("stops reacting to config changes after cleanup", async () => {
      const { initNotificationSync, cleanupNotificationSync } = await import("./notifications");
      initNotificationSync();
      cleanupNotificationSync();

      mockSetEnabled.mockReset();
      configWritable.set({ notifications_enabled: false, notification_volume: 0.5 });

      expect(mockSetEnabled).not.toHaveBeenCalled();
    });

    it("is safe to call when not initialised", async () => {
      const { cleanupNotificationSync } = await import("./notifications");
      expect(() => cleanupNotificationSync()).not.toThrow();
    });

    it("allows re-initialisation after cleanup", async () => {
      const { initNotificationSync, cleanupNotificationSync } = await import("./notifications");
      initNotificationSync();
      cleanupNotificationSync();

      mockSetEnabled.mockReset();
      initNotificationSync();

      expect(mockSetEnabled).toHaveBeenCalledTimes(1);
    });
  });
});
