// Test setup file for Anrubic MCP Server
// This file provides utilities for testing MCP protocol interactions

import { Readable, Writable } from "node:stream";
import { afterEach, beforeEach, mock } from "node:test";

// Global test setup
beforeEach(() => {
  // Reset all mocks before each test
  mock.restoreAll();

  // Reset environment variables
  delete process.env.NODE_ENV;
});

afterEach(() => {
  // Clean up after each test
  mock.restoreAll();
});

// Helper to create mock MCP request
export function createMockMCPRequest(
  method: string,
  params?: any,
  id: number = 1
) {
  return {
    jsonrpc: "2.0",
    id,
    method,
    ...(params && { params }),
  };
}

// Helper to create mock stdio streams for MCP server testing
export function createMockStdioStreams() {
  const mockInput = new Readable({
    read() {
      // Mock readable stream
    },
  });

  const mockOutput = new Writable({
    write(chunk, encoding, callback) {
      // Store output for testing
      this.lastOutput = chunk.toString();
      callback();
    },
  });

  // Add a property to store the last output
  (mockOutput as any).lastOutput = "";

  return { input: mockInput, output: mockOutput };
}

// Helper to parse MCP JSON-RPC response
export function parseMCPResponse(output: string) {
  try {
    const lines = output.trim().split("\n");
    // Find the last line that looks like JSON
    for (let i = lines.length - 1; i >= 0; i--) {
      const line = lines[i].trim();
      if (line.startsWith("{") && line.endsWith("}")) {
        return JSON.parse(line);
      }
    }
    throw new Error("No valid JSON response found");
  } catch (error) {
    throw new Error(`Failed to parse MCP response: ${output}`);
  }
}

// Helper to send MCP request to server
export function sendMCPRequest(input: Readable, request: any) {
  const requestStr = JSON.stringify(request) + "\n";
  input.push(requestStr);
  input.push(null); // End the stream
}

// Mock iolin data for testing
export const mockIolinData = {
  units: [
    {
      id: "faction/grell/unit/lasher",
      slug: "lasher",
      name: "Lasher",
      faction: "grell",
      tier: "T1.5",
      type: "unit",
      inGame: true,
    },
    {
      id: "faction/protectorate/unit/griffin",
      slug: "griffin",
      name: "Griffin",
      faction: "protectorate",
      tier: "T3",
      type: "unit",
      inGame: true,
    },
  ],
  buildings: [
    {
      id: "faction/grell/building/hive",
      slug: "hive",
      name: "Hive",
      faction: "grell",
      tier: "T0",
      type: "building",
      inGame: true,
    },
  ],
  tags: [
    {
      tag: "attacker",
      label: "Attacker",
      description: "Has a basic auto-attack",
    },
    {
      tag: "flyer",
      label: "Flyer",
      description: "Flyer",
    },
    {
      tag: "healer",
      label: "Healer",
      description: "Heals or repairs units or buildings",
    },
  ],
};

// Helper to validate MCP tool schema
export function validateToolSchema(tool: any) {
  const requiredFields = ["name", "inputSchema"];
  for (const field of requiredFields) {
    if (!tool[field]) {
      throw new Error(`Tool missing required field: ${field}`);
    }
  }

  // Validate inputSchema is a valid JSON schema
  if (typeof tool.inputSchema !== "object") {
    throw new Error("Tool inputSchema must be an object");
  }

  if (tool.inputSchema.type !== "object") {
    throw new Error('Tool inputSchema type must be "object"');
  }

  return true;
}

// Helper to validate MCP response format
export function validateMCPResponse(response: any, expectedId?: number) {
  if (!response.jsonrpc || response.jsonrpc !== "2.0") {
    throw new Error("Invalid JSON-RPC version");
  }

  if (expectedId !== undefined && response.id !== expectedId) {
    throw new Error(`Expected id ${expectedId}, got ${response.id}`);
  }

  if (response.error) {
    throw new Error(`MCP Error: ${response.error.message}`);
  }

  if (!response.result) {
    throw new Error("MCP response missing result");
  }

  return true;
}

// Expected MCP tools that should be available
export const expectedMCPTools = [
  "get_tags",
  "get_faction_data",
  "fetch_entity_by_id",
  "all_ids",
  "search_entities",
  "compare_units",
  "get_tech_tree",
  "find_by_tags",
];

// Test data for common MCP tool calls
export const testToolCalls = {
  get_tags: {
    name: "get_tags",
    arguments: {},
  },
  search_entities: {
    name: "search_entities",
    arguments: {
      query: "lasher",
      limit: 3,
    },
  },
  find_by_tags: {
    name: "find_by_tags",
    arguments: {
      tags: ["attacker"],
      matchAll: true,
      limit: 5,
    },
  },
  fetch_entity_by_id: {
    name: "fetch_entity_by_id",
    arguments: {
      id: "faction/protectorate/unit/griffin",
    },
  },
  get_faction_data: {
    name: "get_faction_data",
    arguments: {
      faction: "grell",
    },
  },
};

// Console override for cleaner test output
const originalConsole = { ...console };

export function suppressConsole() {
  global.console = {
    ...console,
    log: mock.fn(),
    warn: mock.fn(),
    error: mock.fn(),
    info: mock.fn(),
  };
}

export function restoreConsole() {
  global.console = originalConsole;
}
