/**
 * MCP Server: Binance Connector
 *
 * Exposes Binance trading capabilities as MCP tools for AI agents.
 * Uses CCXT library to communicate with Binance API.
 *
 * @version 1.0.0
 * @author Trading Platform Trading Platform
 */

import express, { Request, Response, NextFunction } from 'express';
import dotenv from 'dotenv';
import { mcpToolSchemas, toolHandlers, getAllToolDefinitions, toolRequiresConfirmation, getToolRiskLevel } from './tools';
import { getBinanceClient } from './services/binance-client';
import { serverConfig, binanceConfig, validateConfig } from './config';
import { logger } from './utils/logger';

// Load environment variables
dotenv.config();

const app = express();
const PORT = serverConfig.port;
const SERVICE_NAME = 'mcp-binance-connector';
const VERSION = '1.0.0';

// ==========================================
// Middleware
// ==========================================

app.use(express.json());

// Request logging
app.use((req: Request, _res: Response, next: NextFunction) => {
  logger.info(`${req.method} ${req.path}`, {
    ip: req.ip,
    userAgent: req.get('user-agent'),
  });
  next();
});

// MCP API Key authentication (optional, for protected endpoints)
const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
  const mcpKey = req.headers['x-mcp-api-key'];

  // Skip auth if MCP_API_KEY is not configured
  if (!serverConfig.mcpApiKey) {
    next();
    return;
  }

  if (mcpKey !== serverConfig.mcpApiKey) {
    res.status(401).json({ error: 'Invalid MCP API key' });
    return;
  }

  next();
};

// ==========================================
// Health & Status Endpoints
// ==========================================

/**
 * Health check endpoint
 */
app.get('/health', async (_req: Request, res: Response) => {
  try {
    const client = getBinanceClient();
    const binanceConnected = await client.isConnected();
    const binanceConfigured = client.isConfigured();

    res.json({
      status: binanceConnected ? 'healthy' : 'degraded',
      service: SERVICE_NAME,
      version: VERSION,
      timestamp: new Date().toISOString(),
      testnet: binanceConfig.testnet,
      dependencies: {
        binance: binanceConnected ? 'connected' : 'disconnected',
        binanceApiConfigured: binanceConfigured,
      },
    });
  } catch (error) {
    res.json({
      status: 'unhealthy',
      service: SERVICE_NAME,
      version: VERSION,
      timestamp: new Date().toISOString(),
      testnet: binanceConfig.testnet,
      error: error instanceof Error ? error.message : 'Unknown error',
    });
  }
});

/**
 * List available MCP tools
 */
app.get('/tools', (_req: Request, res: Response) => {
  res.json({
    tools: mcpToolSchemas.map((tool) => ({
      name: tool.name,
      description: tool.description,
      riskLevel: (tool as { riskLevel?: string }).riskLevel,
      requiresConfirmation: (tool as { requiresConfirmation?: boolean }).requiresConfirmation,
    })),
    count: mcpToolSchemas.length,
  });
});

/**
 * Get specific tool schema
 */
app.get('/tools/:toolName', (req: Request, res: Response) => {
  const { toolName } = req.params;
  const tool = mcpToolSchemas.find((t) => t.name === toolName);

  if (!tool) {
    res.status(404).json({
      error: `Tool '${toolName}' not found`,
      availableTools: mcpToolSchemas.map((t) => t.name),
    });
    return;
  }

  res.json(tool);
});

// ==========================================
// MCP Tool Execution Endpoints
// ==========================================

/**
 * Execute an MCP tool
 * POST /tools/:toolName
 * Body: { parameters: {...} }
 */
app.post('/tools/:toolName', authMiddleware, async (req: Request, res: Response) => {
  const { toolName } = req.params;
  const { parameters = {} } = req.body;

  // Validate tool exists
  const handler = toolHandlers[toolName];
  if (!handler) {
    res.status(404).json({
      success: false,
      error: `Tool '${toolName}' not found`,
      availableTools: Object.keys(toolHandlers),
    });
    return;
  }

  try {
    logger.info(`Executing tool: ${toolName}`, {
      parameters,
      riskLevel: getToolRiskLevel(toolName),
      requiresConfirmation: toolRequiresConfirmation(toolName),
    });

    const result = await handler(parameters);

    res.json({
      success: true,
      tool: toolName,
      result,
    });
  } catch (error) {
    logger.error(`Tool execution failed: ${toolName}`, { error, parameters });

    // Handle Zod validation errors
    if (error && typeof error === 'object' && 'issues' in error) {
      res.status(400).json({
        success: false,
        error: 'Validation error',
        details: (error as { issues: unknown[] }).issues,
      });
      return;
    }

    res.status(500).json({
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    });
  }
});

// ==========================================
// MCP Protocol Endpoints (Standard)
// ==========================================

/**
 * MCP Initialize
 * Returns server capabilities
 */
app.post('/mcp/initialize', (_req: Request, res: Response) => {
  res.json({
    protocolVersion: '2024-11-05',
    capabilities: {
      tools: {},
    },
    serverInfo: {
      name: SERVICE_NAME,
      version: VERSION,
    },
  });
});

/**
 * MCP List Tools
 * Returns all available tools in MCP format
 */
app.post('/mcp/tools/list', (_req: Request, res: Response) => {
  res.json({
    tools: getAllToolDefinitions(),
  });
});

/**
 * MCP Call Tool
 * Execute a tool with parameters
 */
app.post('/mcp/tools/call', authMiddleware, async (req: Request, res: Response) => {
  const { name, arguments: args = {} } = req.body;

  if (!name) {
    res.status(400).json({
      error: {
        code: 'invalid_request',
        message: 'Tool name is required',
      },
    });
    return;
  }

  const handler = toolHandlers[name];
  if (!handler) {
    res.status(404).json({
      error: {
        code: 'unknown_tool',
        message: `Tool '${name}' not found`,
      },
    });
    return;
  }

  try {
    const result = await handler(args);
    res.json(result);
  } catch (error) {
    // Handle Zod validation errors
    if (error && typeof error === 'object' && 'issues' in error) {
      res.status(400).json({
        error: {
          code: 'invalid_params',
          message: 'Invalid tool parameters',
          data: (error as { issues: unknown[] }).issues,
        },
      });
      return;
    }

    res.status(500).json({
      error: {
        code: 'internal_error',
        message: error instanceof Error ? error.message : 'Unknown error',
      },
    });
  }
});

// ==========================================
// Error Handler
// ==========================================

app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
  logger.error('Unhandled error', { error: err });
  res.status(500).json({
    error: 'Internal server error',
    message: err.message,
  });
});

// ==========================================
// Start Server
// ==========================================

// Validate configuration before starting
const configValidation = validateConfig();
if (!configValidation.valid) {
  logger.warn('Configuration warnings', { errors: configValidation.errors });
}

app.listen(PORT, () => {
  console.log('');
  console.log('================================================================');
  console.log('         MCP Binance Connector - Trading Platform Trading Platform     ');
  console.log('================================================================');
  console.log(`  Service: ${SERVICE_NAME}`);
  console.log(`  Version: ${VERSION}`);
  console.log(`  Port: ${PORT}`);
  console.log(`  Environment: ${serverConfig.nodeEnv}`);
  console.log(`  Testnet Mode: ${binanceConfig.testnet ? 'ENABLED' : 'DISABLED'}`);
  console.log(`  API Configured: ${binanceConfig.apiKey ? 'Yes' : 'No'}`);
  console.log('----------------------------------------------------------------');
  console.log('  Endpoints:');
  console.log(`  - Health: http://localhost:${PORT}/health`);
  console.log(`  - Tools:  http://localhost:${PORT}/tools`);
  console.log('----------------------------------------------------------------');
  console.log('  MCP Tools Available:');
  mcpToolSchemas.forEach((tool) => {
    const risk = (tool as { riskLevel?: string }).riskLevel || 'N/A';
    const confirm = (tool as { requiresConfirmation?: boolean }).requiresConfirmation ? ' (!)' : '';
    console.log(`  - ${tool.name} [${risk}]${confirm}`);
  });
  console.log('================================================================');
  console.log('');
});

// ==========================================
// Graceful Shutdown
// ==========================================

process.on('SIGTERM', () => {
  logger.info('Received SIGTERM, shutting down gracefully...');
  process.exit(0);
});

process.on('SIGINT', () => {
  logger.info('Received SIGINT, shutting down gracefully...');
  process.exit(0);
});

export default app;
