import {
  SystemState,
  TargetServer,
  ConnectedClient,
  ConnectedClientCluster,
  Usage,
} from "@mcpx/shared-model";
import { DELAY_30_SEC, DELAY_5_MIN } from "../constants/delays";

/**
 * Base mock SystemState with minimal required fields
 */
const createBaseSystemState = (): Omit<
  SystemState,
  "targetServers" | "connectedClients" | "connectedClientClusters"
> => ({
  usage: {
    callCount: 0,
    lastCalledAt: undefined,
  },
  lastUpdatedAt: new Date(),
  mcpxVersion: "1.0.0",
});

/**
 * Zero state - no servers, no agents
 */
export const zeroState: SystemState = {
  ...createBaseSystemState(),
  targetServers: [],
  connectedClients: [],
  connectedClientClusters: [],
};

/**
 * Configuration for creating mock servers
 */
export interface MockServerConfig {
  name: string;
  type?: "stdio" | "sse" | "streamable-http";
  state?: "connecting" | "connected" | "pending-auth" | "connection-failed";
  toolCount?: number;
  isActive?: boolean; // If true, sets lastCalledAt to recent date
  icon?: string;
  error?: Error;
}

/**
 * Configuration for creating mock agents
 */
export interface MockAgentConfig {
  name: string;
  sessionIds?: string[];
  provider?: string;
  model?: string;
  isActive?: boolean;
}

/**
 * Create a mock server based on configuration
 */
export const createMockServer = (config: MockServerConfig): TargetServer => {
  const now = new Date();
  const activeDate = config.isActive
    ? new Date(now.getTime() - DELAY_5_MIN)
    : undefined; // 5 minutes ago if active

  const tools = Array.from({ length: config.toolCount || 3 }, (_, i) => ({
    name: `tool-${i + 1}`,
    description: `Tool ${i + 1} description`,
    inputSchema: {
      type: "object" as const,
      properties: {},
    },
    usage: {
      callCount: config.isActive ? 10 : 0,
      lastCalledAt: config.isActive ? activeDate : undefined,
    } as Usage,
  }));

  const baseServer = {
    name: config.name,
    icon: config.icon,
    tools,
    originalTools: [],
    usage: {
      callCount: config.isActive ? 50 : 0,
      lastCalledAt: activeDate,
    } as Usage,
  };

  const stateType = config.state || "connected";
  const state: TargetServer["state"] = (() => {
    switch (stateType) {
      case "connecting":
        return { type: "connecting" };
      case "connected":
        return { type: "connected" };
      case "pending-auth":
        return { type: "pending-auth" };
      case "connection-failed":
        return {
          type: "connection-failed",
          error: config.error || new Error("Connection failed"),
        };
    }
  })();

  const serverType = config.type || "stdio";

  if (serverType === "stdio") {
    return {
      _type: "stdio",
      ...baseServer,
      state,
      command: "node",
      args: ["server.js"],
      env: {},
    };
  } else if (serverType === "sse") {
    return {
      _type: "sse",
      ...baseServer,
      state,
      url: "http://localhost:3000/sse",
    };
  } else {
    return {
      _type: "streamable-http",
      ...baseServer,
      state,
      url: "http://localhost:3000/streamable",
      headers: {},
    };
  }
};

/**
 * Create a mock agent based on configuration
 */
export const createMockAgent = (
  config: MockAgentConfig,
): {
  client: ConnectedClient;
  cluster: ConnectedClientCluster;
} => {
  const sessionId = `session-${config.name}-${Date.now()}`;
  const sessionIds = config.sessionIds || [sessionId];
  const now = new Date();
  // isActive requires activity within last 1 minute, so set to 30 seconds ago
  const activeDate = config.isActive
    ? new Date(now.getTime() - DELAY_30_SEC)
    : undefined;

  const client: ConnectedClient = {
    sessionId: sessionIds[0],
    clientId: `client-${config.name}`,
    usage: {
      callCount: config.isActive ? 20 : 0,
      lastCalledAt: activeDate,
    } as Usage,
    llm: {
      provider: config.provider || "openai",
      modelId: config.model || "gpt-4",
    },
  };

  const cluster: ConnectedClientCluster = {
    identityType: "clientName",
    clientName: config.name,
    sessionIds,
    usage: {
      callCount: config.isActive ? 20 : 0,
      lastCalledAt: activeDate,
    } as Usage,
  };

  return { client, cluster };
};

/**
 * Create a SystemState with specified number of servers and agents
 */
export const createSystemState = (options: {
  serverCount?: number;
  agentCount?: number;
  serverConfig?: Partial<MockServerConfig>;
  agentConfig?: Partial<MockAgentConfig>;
}): SystemState => {
  const {
    serverCount = 0,
    agentCount = 0,
    serverConfig = {},
    agentConfig = {},
  } = options;

  const servers: TargetServer[] = Array.from({ length: serverCount }, (_, i) =>
    createMockServer({
      name: `server-${i + 1}`,
      ...serverConfig,
    }),
  );

  const clients: ConnectedClient[] = [];
  const clusters: ConnectedClientCluster[] = [];

  Array.from({ length: agentCount }, (_, i) => {
    const { client, cluster } = createMockAgent({
      name: `agent-${i + 1}`,
      ...agentConfig,
    });
    clients.push(client);
    clusters.push(cluster);
  });

  return {
    ...createBaseSystemState(),
    targetServers: servers,
    connectedClients: clients,
    connectedClientClusters: clusters,
  };
};

/**
 * Predefined system states for common test scenarios
 */
export const mockSystemStates = {
  zero: zeroState,

  oneServer: createSystemState({ serverCount: 1 }),

  multipleServers: createSystemState({ serverCount: 3 }),

  oneAgent: createSystemState({ agentCount: 1 }),

  multipleAgents: createSystemState({ agentCount: 2 }),

  oneServerOneAgent: createSystemState({ serverCount: 1, agentCount: 1 }),

  multipleServersMultipleAgents: createSystemState({
    serverCount: 3,
    agentCount: 2,
  }),

  activeServers: createSystemState({
    serverCount: 2,
    serverConfig: { isActive: true },
  }),

  pendingAuthServers: createSystemState({
    serverCount: 2,
    serverConfig: { state: "pending-auth" },
  }),

  failedServers: createSystemState({
    serverCount: 2,
    serverConfig: { state: "connection-failed" },
  }),

  mixedServerStates: (): SystemState => ({
    ...createBaseSystemState(),
    targetServers: [
      createMockServer({
        name: "server-connected",
        state: "connected",
        isActive: true,
      }),
      createMockServer({ name: "server-pending", state: "pending-auth" }),
      createMockServer({ name: "server-failed", state: "connection-failed" }),
    ],
    connectedClients: [],
    connectedClientClusters: [],
  }),

  serversWithManyTools: createSystemState({
    serverCount: 2,
    serverConfig: { toolCount: 10 },
  }),
};
