import { describe, expect, it, mock } from "bun:test";
import { createNewsBridge } from "./newsBridge";

describe("createNewsBridge", () => {
  it("passes request payloads to the expected Tauri commands", async () => {
    const invoke = mock(
      async <T>(
        command: string,
        args?: Record<string, unknown>,
      ): Promise<T> => {
        if (command === "query_news_feed") {
          return {
            articles: [],
            total: 0,
            sources: [],
          } as T;
        }

        if (command === "refresh_news_feed") {
          return {
            feedsChecked: 1,
            feedsSucceeded: 1,
            feedsFailed: 0,
            newArticles: 0,
            updatedArticles: 0,
            unchangedArticles: 0,
            finishedAt: "2026-04-08T10:00:00Z",
          } as T;
        }

        if (command === "get_news_feed_config") {
          return [
            {
              id: "fed",
              name: "Federal Reserve",
              url: "https://example.com/fed.xml",
              refreshMinutes: 15,
            },
          ] as T;
        }

        if (command === "save_news_feed_config") {
          expect(args).toEqual({
            request: {
              feeds: [
                {
                  id: "custom",
                  name: "Custom Feed",
                  url: "https://example.com/custom.xml",
                  refreshMinutes: 30,
                },
              ],
            },
          });
          return [
            {
              id: "custom",
              name: "Custom Feed",
              url: "https://example.com/custom.xml",
              refreshMinutes: 30,
            },
          ] as T;
        }

        if (command === "reset_news_feed_config") {
          return [] as T;
        }

        expect(command).toBe("update_news_article_state");
        expect(args).toEqual({
          request: {
            articleId: "article-1",
            isSaved: true,
          },
        });
        return undefined as T;
      },
    );
    const bridge = createNewsBridge(invoke);

    const query = await bridge.queryNewsFeed({ ticker: "NVDA", limit: 20 });
    const refresh = await bridge.refreshNewsFeed({ force: true });
    const config = await bridge.getNewsFeedConfig();
    const savedFeeds = await bridge.saveNewsFeedConfig({
      feeds: [
        {
          id: "custom",
          name: "Custom Feed",
          url: "https://example.com/custom.xml",
          refreshMinutes: 30,
        },
      ],
    });
    const resetFeeds = await bridge.resetNewsFeedConfig();
    await bridge.updateNewsArticleState({
      articleId: "article-1",
      isSaved: true,
    });

    expect(invoke).toHaveBeenNthCalledWith(1, "query_news_feed", {
      request: { ticker: "NVDA", limit: 20 },
    });
    expect(invoke).toHaveBeenNthCalledWith(2, "refresh_news_feed", {
      request: { force: true },
    });
    expect(invoke).toHaveBeenNthCalledWith(3, "get_news_feed_config");
    expect(invoke).toHaveBeenNthCalledWith(4, "save_news_feed_config", {
      request: {
        feeds: [
          {
            id: "custom",
            name: "Custom Feed",
            url: "https://example.com/custom.xml",
            refreshMinutes: 30,
          },
        ],
      },
    });
    expect(invoke).toHaveBeenNthCalledWith(5, "reset_news_feed_config");
    expect(query.total).toBe(0);
    expect(refresh.feedsChecked).toBe(1);
    expect(config[0]?.id).toBe("fed");
    expect(savedFeeds[0]?.id).toBe("custom");
    expect(resetFeeds).toEqual([]);
  });

  it("subscribes to news updates with the expected event name", async () => {
    const listen = mock(
      async <T>(
        _event: string,
        handler: (event: { payload: T }) => void,
      ): Promise<() => void> => {
        handler({
          payload: {
            feedsChecked: 1,
            feedsSucceeded: 1,
            feedsFailed: 0,
            newArticles: 2,
            updatedArticles: 1,
            unchangedArticles: 0,
            finishedAt: "2026-04-08T10:00:00Z",
          } as T,
        });
        return () => {};
      },
    );
    const handler = mock(() => {});
    const bridge = createNewsBridge(async () => undefined as never, listen);

    await bridge.listenForUpdates(handler);

    expect(listen).toHaveBeenCalledWith(
      "news_feed_updated",
      expect.any(Function),
    );
    expect(handler).toHaveBeenCalledWith({
      feedsChecked: 1,
      feedsSucceeded: 1,
      feedsFailed: 0,
      newArticles: 2,
      updatedArticles: 1,
      unchangedArticles: 0,
      finishedAt: "2026-04-08T10:00:00Z",
    });
  });
});
