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

vi.mock("@/core/api/fetcher", () => ({
  fetch: vi.fn(),
}));

vi.mock("@/core/config", () => ({
  getBackendBaseURL: () => "/backend",
}));

import { fetch as fetcher } from "@/core/api/fetcher";
import {
  connectChannelProvider,
  disconnectChannelConnection,
  listChannelConnections,
  listChannelProviders,
} from "@/core/channels/api";

const mockedFetch = vi.mocked(fetcher);

function jsonResponse(status: number, body: unknown): Response {
  return new Response(JSON.stringify(body), {
    status,
    statusText: status >= 400 ? "Bad Request" : "OK",
    headers: { "Content-Type": "application/json" },
  });
}

beforeEach(() => {
  mockedFetch.mockReset();
});

describe("channels api", () => {
  test("loads provider catalog", async () => {
    mockedFetch.mockResolvedValueOnce(
      jsonResponse(200, {
        enabled: true,
        providers: [
          {
            provider: "telegram",
            display_name: "Telegram",
            enabled: true,
            configured: true,
            auth_mode: "deep_link",
            connection_status: "not_connected",
          },
        ],
      }),
    );

    await expect(listChannelProviders()).resolves.toMatchObject({
      enabled: true,
      providers: [{ provider: "telegram", display_name: "Telegram" }],
    });
    expect(mockedFetch).toHaveBeenCalledWith("/backend/api/channels/providers");
  });

  test("loads current user's connections", async () => {
    mockedFetch.mockResolvedValueOnce(
      jsonResponse(200, {
        connections: [
          {
            id: "connection-1",
            provider: "telegram",
            status: "connected",
            external_account_name: "Alice",
            scopes: [],
            metadata: {},
          },
        ],
      }),
    );

    await expect(listChannelConnections()).resolves.toMatchObject([
      { id: "connection-1", provider: "telegram", status: "connected" },
    ]);
    expect(mockedFetch).toHaveBeenCalledWith(
      "/backend/api/channels/connections",
    );
  });

  test("starts a provider connection flow", async () => {
    mockedFetch.mockResolvedValueOnce(
      jsonResponse(200, {
        provider: "telegram",
        mode: "deep_link",
        url: "https://t.me/deerflow_bot?start=state",
        expires_in: 600,
      }),
    );

    await expect(connectChannelProvider("telegram")).resolves.toMatchObject({
      provider: "telegram",
      url: "https://t.me/deerflow_bot?start=state",
    });
    expect(mockedFetch).toHaveBeenCalledWith(
      "/backend/api/channels/telegram/connect",
      { method: "POST" },
    );
  });

  test("disconnects a channel connection", async () => {
    mockedFetch.mockResolvedValueOnce(new Response(null, { status: 204 }));

    await expect(
      disconnectChannelConnection("connection-1"),
    ).resolves.toBeUndefined();
    expect(mockedFetch).toHaveBeenCalledWith(
      "/backend/api/channels/connections/connection-1",
      { method: "DELETE" },
    );
  });

  test("uses backend detail for failed requests", async () => {
    mockedFetch.mockResolvedValueOnce(
      jsonResponse(400, { detail: "Channel provider is not configured" }),
    );

    await expect(connectChannelProvider("slack")).rejects.toThrow(
      "Channel provider is not configured",
    );
  });
});
