/**
 * Favorites service tests
 *
 * TRACES: UR-017 | DR-021
 */

import { describe, it, expect, beforeEach, vi } from "vitest";
import { toggleFavorite } from "./favorites";

vi.mock("@tauri-apps/api/core", () => ({
  invoke: vi.fn(async (command: string) => {
    if (command === "storage_toggle_favorite") {
      return undefined;
    }
    if (command === "storage_mark_synced") {
      return undefined;
    }
    return null;
  }),
}));

vi.mock("$lib/stores/auth", () => ({
  auth: {
    getUserId: vi.fn(() => "user-123"),
    getRepository: vi.fn(() => ({
      markFavorite: vi.fn(async () => undefined),
      unmarkFavorite: vi.fn(async () => undefined),
    })),
  },
}));

describe("favorites service", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("toggleFavorite", () => {
    it("should toggle favorite to true", async () => {
      const result = await toggleFavorite("item-123", false);
      expect(result).toBe(true);
    });

    it("should toggle favorite to false", async () => {
      const result = await toggleFavorite("item-123", true);
      expect(result).toBe(false);
    });

    it("should update local database", async () => {
      const { invoke } = await import("@tauri-apps/api/core");
      const invokeSpy = vi.mocked(invoke);

      await toggleFavorite("item-123", false);

      const call = invokeSpy.mock.calls.find(
        (c) => c[0] === "storage_toggle_favorite"
      );
      expect(call).toBeDefined();
      expect(call![1]).toHaveProperty("itemId", "item-123");
      expect(call![1]).toHaveProperty("isFavorite", true);
    });

    it("should include userId in storage call", async () => {
      const { invoke } = await import("@tauri-apps/api/core");
      const invokeSpy = vi.mocked(invoke);

      await toggleFavorite("item-123", false);

      const call = invokeSpy.mock.calls.find(
        (c) => c[0] === "storage_toggle_favorite"
      );
      expect(call![1]).toHaveProperty("userId", "user-123");
    });

    it("should sync to server when marking as favorite", async () => {
      const { auth } = await import("$lib/stores/auth");
      const authModule = vi.mocked(auth);
      const mockRepo = {
        markFavorite: vi.fn(async () => undefined),
        unmarkFavorite: vi.fn(async () => undefined),
      };
      authModule.getRepository = vi.fn(() => mockRepo as any);

      await toggleFavorite("item-123", false);

      expect(mockRepo.markFavorite).toHaveBeenCalledWith("item-123");
    });

    it("should sync to server when unmarking as favorite", async () => {
      const { auth } = await import("$lib/stores/auth");
      const authModule = vi.mocked(auth);
      const mockRepo = {
        markFavorite: vi.fn(async () => undefined),
        unmarkFavorite: vi.fn(async () => undefined),
      };
      authModule.getRepository = vi.fn(() => mockRepo as any);

      await toggleFavorite("item-123", true);

      expect(mockRepo.unmarkFavorite).toHaveBeenCalledWith("item-123");
    });

    it("should mark as synced after successful server update", async () => {
      const { invoke } = await import("@tauri-apps/api/core");
      const invokeSpy = vi.mocked(invoke);

      await toggleFavorite("item-123", false);

      const markSyncedCall = invokeSpy.mock.calls.find(
        (c) => c[0] === "storage_mark_synced"
      );
      expect(markSyncedCall).toBeDefined();
      expect(markSyncedCall![1]).toHaveProperty("itemId", "item-123");
    });

    it("should throw error if not authenticated", async () => {
      const { auth } = await import("$lib/stores/auth");
      const authModule = vi.mocked(auth);
      authModule.getUserId = vi.fn(() => null);

      await expect(toggleFavorite("item-123", false)).rejects.toThrow(
        "Not authenticated"
      );
    });

    it("should handle server sync failure gracefully", async () => {
      const { auth } = await import("$lib/stores/auth");
      const authModule = vi.mocked(auth);
      const mockRepo = {
        markFavorite: vi.fn(async () => {
          throw new Error("Server error");
        }),
        unmarkFavorite: vi.fn(async () => undefined),
      };
      authModule.getRepository = vi.fn(() => mockRepo as any);

      // Ensure getUserId returns a value for this test
      authModule.getUserId = vi.fn(() => "user-123");

      // Should not throw, but return the new favorite state
      const result = await toggleFavorite("item-123", false);
      expect(result).toBe(true);
    });

    it("should handle multiple toggles", async () => {
      const { auth } = await import("$lib/stores/auth");
      const authModule = vi.mocked(auth);
      authModule.getUserId = vi.fn(() => "user-123");

      let result = await toggleFavorite("item-123", false);
      expect(result).toBe(true);

      result = await toggleFavorite("item-123", true);
      expect(result).toBe(false);

      result = await toggleFavorite("item-123", false);
      expect(result).toBe(true);
    });
  });
});
