/**
 * Federation API Client Tests
 * Tests for mock data NODE_ENV gating (SEC-WEB-37)
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import * as client from "./client";
import {
  getMockConnections,
  fetchConnections,
  fetchConnection,
  fetchInstanceIdentity,
  updateInstanceConfiguration,
  regenerateInstanceKeys,
  FederationConnectionStatus,
} from "./federation";

// Mock the API client
vi.mock("./client", () => ({
  apiGet: vi.fn(),
  apiPost: vi.fn(),
  apiPatch: vi.fn(),
}));

describe("Federation API", () => {
  describe("getMockConnections", () => {
    it("should return mock connections in development mode", () => {
      vi.stubEnv("NODE_ENV", "development");

      const connections = getMockConnections();

      expect(connections).toHaveLength(3);
      expect(connections[0]?.id).toBe("conn-1");
      expect(connections[0]?.remoteUrl).toBe("https://mosaic.work.example.com");
      expect(connections[1]?.id).toBe("conn-2");
      expect(connections[2]?.id).toBe("conn-3");
    });

    it("should return empty array in production mode", () => {
      vi.stubEnv("NODE_ENV", "production");

      const connections = getMockConnections();

      expect(connections).toEqual([]);
      expect(connections).toHaveLength(0);
    });

    it("should return empty array in test mode", () => {
      vi.stubEnv("NODE_ENV", "test");

      const connections = getMockConnections();

      expect(connections).toEqual([]);
      expect(connections).toHaveLength(0);
    });

    it("should include expected connection statuses in development", () => {
      vi.stubEnv("NODE_ENV", "development");

      const connections = getMockConnections();

      expect(connections[0]?.status).toBe(FederationConnectionStatus.ACTIVE);
      expect(connections[1]?.status).toBe(FederationConnectionStatus.PENDING);
      expect(connections[2]?.status).toBe(FederationConnectionStatus.DISCONNECTED);
    });

    it("should include capabilities in development mock data", () => {
      vi.stubEnv("NODE_ENV", "development");

      const connections = getMockConnections();

      expect(connections[0]?.remoteCapabilities).toEqual({
        supportsQuery: true,
        supportsCommand: true,
        supportsEvent: true,
        supportsAgentSpawn: true,
        protocolVersion: "1.0",
      });
    });

    it("should not expose mock public keys in production", () => {
      vi.stubEnv("NODE_ENV", "production");

      const connections = getMockConnections();

      // In production, no connections should be returned at all
      expect(connections).toHaveLength(0);
      // Verify no public key data is accessible
      const hasPublicKeys = connections.some((c) => c.remotePublicKey);
      expect(hasPublicKeys).toBe(false);
    });
  });

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

    it("should call the connections endpoint without filters", async () => {
      const mockResponse = [{ id: "conn-1" }];

      vi.mocked(client.apiGet).mockResolvedValue(mockResponse);

      const result = await fetchConnections();

      expect(client.apiGet).toHaveBeenCalledWith("/api/v1/federation/connections");
      expect(result).toEqual(mockResponse);
    });

    it("should include status filter in query string", async () => {
      const mockResponse = [{ id: "conn-1" }];

      vi.mocked(client.apiGet).mockResolvedValue(mockResponse);

      const result = await fetchConnections(FederationConnectionStatus.ACTIVE);

      expect(client.apiGet).toHaveBeenCalledWith("/api/v1/federation/connections?status=ACTIVE");
      expect(result).toEqual(mockResponse);
    });
  });

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

    it("should fetch a single connection by ID", async () => {
      const mockResponse = { id: "conn-1", remoteUrl: "https://example.com" };

      vi.mocked(client.apiGet).mockResolvedValue(mockResponse);

      const result = await fetchConnection("conn-1");

      expect(client.apiGet).toHaveBeenCalledWith("/api/v1/federation/connections/conn-1");
      expect(result).toEqual(mockResponse);
    });
  });

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

    it("should fetch the instance identity", async () => {
      const mockResponse = { id: "inst-1", name: "Test Instance" };

      vi.mocked(client.apiGet).mockResolvedValue(mockResponse);

      const result = await fetchInstanceIdentity();

      expect(client.apiGet).toHaveBeenCalledWith("/api/v1/federation/instance");
      expect(result).toEqual(mockResponse);
    });
  });

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

    it("should update instance configuration", async () => {
      const mockResponse = { id: "inst-1", name: "Updated Instance" };

      vi.mocked(client.apiPatch).mockResolvedValue(mockResponse);

      const result = await updateInstanceConfiguration({ name: "Updated Instance" });

      expect(client.apiPatch).toHaveBeenCalledWith("/api/v1/federation/instance", {
        name: "Updated Instance",
      });
      expect(result).toEqual(mockResponse);
    });
  });

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

    it("should regenerate instance keys", async () => {
      const mockResponse = { id: "inst-1", publicKey: "new-key" };

      vi.mocked(client.apiPost).mockResolvedValue(mockResponse);

      const result = await regenerateInstanceKeys();

      expect(client.apiPost).toHaveBeenCalledWith(
        "/api/v1/federation/instance/regenerate-keys",
        {}
      );
      expect(result).toEqual(mockResponse);
    });
  });
});
