/**
 * Synor Liquidity Aggregator
 * Cross-chain DEX routing with optimal pricing
 *
 * Port: 17520
 * Endpoints:
 *   GET /health - Health check
 *   GET /sources - Available liquidity sources
 *   GET /quote - Get best price quote
 *   GET /routes - Get optimal routing
 *   POST /swap - Execute swap (simulated)
 */

const http = require('http');

const PORT = process.env.PORT || 17520;
const AGGREGATION_FEE_BPS = parseInt(process.env.AGGREGATION_FEE_BPS) || 5;
const MAX_SLIPPAGE_BPS = parseInt(process.env.MAX_SLIPPAGE_BPS) || 100;

// Liquidity sources (simulated)
const sources = new Map([
  ['synor', { id: 'synor', name: 'Synor DEX', type: 'amm', chain: 'synor', active: true, liquidity: 5000000 }],
  ['osmosis', { id: 'osmosis', name: 'Osmosis', type: 'amm', chain: 'cosmos', active: true, liquidity: 50000000 }],
  ['dydx', { id: 'dydx', name: 'dYdX', type: 'orderbook', chain: 'cosmos', active: true, liquidity: 100000000 }],
  ['uniswap', { id: 'uniswap', name: 'Uniswap V3', type: 'amm', chain: 'ethereum', active: true, liquidity: 500000000 }],
]);

// Simulated price quotes
const baseQuotes = {
  'BTC/USDT': 45000,
  'ETH/USDT': 2500,
  'SYNOR/USDT': 1.50,
  'SOL/USDT': 95,
  'ATOM/USDT': 8.50,
};

// Get quote from source with slippage simulation
function getQuoteFromSource(sourceId, tokenIn, tokenOut, amountIn) {
  const source = sources.get(sourceId);
  if (!source || !source.active) return null;

  const pair = `${tokenIn}/${tokenOut}`;
  const basePrice = baseQuotes[pair] || baseQuotes[`${tokenOut}/${tokenIn}`];
  if (!basePrice) return null;

  // Add random spread based on source
  const spreadMultiplier = source.type === 'orderbook' ? 0.9995 : 0.999; // Orderbooks typically tighter
  const slippageImpact = (amountIn / source.liquidity) * 0.01; // Price impact

  const effectivePrice = basePrice * spreadMultiplier * (1 - slippageImpact);
  const amountOut = (amountIn / effectivePrice) * (1 - AGGREGATION_FEE_BPS / 10000);

  return {
    source: sourceId,
    sourceName: source.name,
    tokenIn,
    tokenOut,
    amountIn,
    amountOut,
    effectivePrice,
    priceImpact: slippageImpact * 100,
    fee: amountIn * (AGGREGATION_FEE_BPS / 10000),
    timestamp: Date.now(),
  };
}

// Find best route
function findBestRoute(tokenIn, tokenOut, amountIn) {
  const quotes = [];

  for (const [sourceId] of sources) {
    const quote = getQuoteFromSource(sourceId, tokenIn, tokenOut, amountIn);
    if (quote) quotes.push(quote);
  }

  if (quotes.length === 0) return null;

  // Sort by best output amount
  quotes.sort((a, b) => b.amountOut - a.amountOut);

  // For large amounts, consider split routing
  const bestSingle = quotes[0];

  // Simple split route: 60% to best, 40% to second best
  if (quotes.length >= 2 && amountIn > 10000) {
    const splitRoute = {
      type: 'split',
      routes: [
        { ...getQuoteFromSource(quotes[0].source, tokenIn, tokenOut, amountIn * 0.6), percentage: 60 },
        { ...getQuoteFromSource(quotes[1].source, tokenIn, tokenOut, amountIn * 0.4), percentage: 40 },
      ],
      totalAmountOut: 0,
    };
    splitRoute.routes.forEach(r => splitRoute.totalAmountOut += r.amountOut);

    // Use split if better
    if (splitRoute.totalAmountOut > bestSingle.amountOut) {
      return { best: splitRoute, alternatives: quotes.slice(0, 3) };
    }
  }

  return { best: bestSingle, alternatives: quotes.slice(1, 4) };
}

// Parse JSON body
function parseBody(req) {
  return new Promise((resolve, reject) => {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      try {
        resolve(body ? JSON.parse(body) : {});
      } catch (e) {
        reject(e);
      }
    });
  });
}

// HTTP Server
const server = http.createServer(async (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }

  const url = new URL(req.url, `http://localhost:${PORT}`);
  const path = url.pathname;

  try {
    // Health check
    if (path === '/health') {
      const activeSources = Array.from(sources.values()).filter(s => s.active).length;
      res.writeHead(200);
      res.end(JSON.stringify({
        status: 'healthy',
        sources: activeSources,
        feeBps: AGGREGATION_FEE_BPS,
        timestamp: Date.now(),
      }));
      return;
    }

    // Available sources
    if (path === '/sources') {
      res.writeHead(200);
      res.end(JSON.stringify({
        sources: Array.from(sources.values()),
        count: sources.size,
      }));
      return;
    }

    // Get quote
    if (path === '/quote') {
      const tokenIn = url.searchParams.get('tokenIn')?.toUpperCase();
      const tokenOut = url.searchParams.get('tokenOut')?.toUpperCase();
      const amountIn = parseFloat(url.searchParams.get('amount'));

      if (!tokenIn || !tokenOut || !amountIn) {
        res.writeHead(400);
        res.end(JSON.stringify({ error: 'Missing tokenIn, tokenOut, or amount' }));
        return;
      }

      const result = findBestRoute(tokenIn, tokenOut, amountIn);
      if (!result) {
        res.writeHead(404);
        res.end(JSON.stringify({ error: 'No route found', tokenIn, tokenOut }));
        return;
      }

      res.writeHead(200);
      res.end(JSON.stringify(result));
      return;
    }

    // Get routes (same as quote but more detailed)
    if (path === '/routes') {
      const tokenIn = url.searchParams.get('tokenIn')?.toUpperCase();
      const tokenOut = url.searchParams.get('tokenOut')?.toUpperCase();
      const amountIn = parseFloat(url.searchParams.get('amount'));

      if (!tokenIn || !tokenOut || !amountIn) {
        res.writeHead(400);
        res.end(JSON.stringify({ error: 'Missing parameters' }));
        return;
      }

      const quotes = [];
      for (const [sourceId] of sources) {
        const quote = getQuoteFromSource(sourceId, tokenIn, tokenOut, amountIn);
        if (quote) quotes.push(quote);
      }

      quotes.sort((a, b) => b.amountOut - a.amountOut);

      res.writeHead(200);
      res.end(JSON.stringify({
        tokenIn,
        tokenOut,
        amountIn,
        routes: quotes,
        bestSource: quotes[0]?.source,
      }));
      return;
    }

    // Execute swap (simulated)
    if (path === '/swap' && req.method === 'POST') {
      const body = await parseBody(req);
      const { tokenIn, tokenOut, amountIn, minAmountOut, route, sender } = body;

      if (!tokenIn || !tokenOut || !amountIn || !sender) {
        res.writeHead(400);
        res.end(JSON.stringify({ error: 'Missing required fields' }));
        return;
      }

      const result = findBestRoute(tokenIn, tokenOut, amountIn);
      if (!result) {
        res.writeHead(400);
        res.end(JSON.stringify({ error: 'No route available' }));
        return;
      }

      const amountOut = result.best.type === 'split' ? result.best.totalAmountOut : result.best.amountOut;

      if (minAmountOut && amountOut < minAmountOut) {
        res.writeHead(400);
        res.end(JSON.stringify({ error: 'Slippage too high', expected: minAmountOut, actual: amountOut }));
        return;
      }

      // Simulate transaction
      const txId = `0x${Math.random().toString(16).slice(2)}${Date.now().toString(16)}`;

      res.writeHead(200);
      res.end(JSON.stringify({
        success: true,
        txId,
        tokenIn,
        tokenOut,
        amountIn,
        amountOut,
        route: result.best,
        sender,
        timestamp: Date.now(),
      }));
      return;
    }

    // Default
    res.writeHead(404);
    res.end(JSON.stringify({ error: 'Not found' }));
  } catch (err) {
    res.writeHead(500);
    res.end(JSON.stringify({ error: err.message }));
  }
});

server.listen(PORT, '0.0.0.0', () => {
  console.log(`Liquidity Aggregator running on port ${PORT}`);
  console.log(`Sources: ${Array.from(sources.values()).map(s => s.name).join(', ')}`);
  console.log(`Aggregation Fee: ${AGGREGATION_FEE_BPS / 100}%`);
  console.log('Endpoints:');
  console.log('  GET /health - Health check');
  console.log('  GET /sources - Available liquidity sources');
  console.log('  GET /quote?tokenIn=X&tokenOut=Y&amount=Z - Get best quote');
  console.log('  GET /routes?tokenIn=X&tokenOut=Y&amount=Z - Get all routes');
  console.log('  POST /swap - Execute swap');
});
