import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';

interface IxMatrixQuery {
  ix_id?: string;
}

async function fetchWithRetry(url: string, retries = 1, timeout = 10000): Promise<any> {
  for (let i = 0; i <= retries; i++) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);
    try {
      const response = await fetch(url, { signal: controller.signal });
      clearTimeout(timeoutId);
      if (!response.ok) {
        if (i === retries) throw new Error(`HTTP ${response.status}`);
        continue;
      }
      return await response.json();
    } catch (e) {
      clearTimeout(timeoutId);
      if (i === retries) throw e;
      await new Promise(r => setTimeout(r, 1500));
    }
  }
}

export async function ixMatrixRoutes(fastify: FastifyInstance): Promise<void> {
  fastify.get<{ Querystring: IxMatrixQuery }>(
    '/ix-matrix',
    async (request: FastifyRequest<{ Querystring: IxMatrixQuery }>, reply: FastifyReply) => {
      let ixIdStr = request.query.ix_id || '';
      const ixId = ixIdStr.replace(/[^0-9]/g, '');
      
      reply.header('Access-Control-Allow-Origin', '*');
      reply.header('Cache-Control', 'public, max-age=3600');

      if (!ixId) {
        return reply.status(400).send({ error: 'ix_id required' });
      }

      try {
        const PEERINGDB_API_URL = 'https://www.peeringdb.com/api';
        
        const [netixData, ixData] = await Promise.all([
          fetchWithRetry(`${PEERINGDB_API_URL}/netixlan?ix_id=${ixId}&depth=1&limit=200`, 1, 15000),
          fetchWithRetry(`${PEERINGDB_API_URL}/ix/${ixId}`, 1, 10000),
        ]);
        
        const ix = ixData && ixData.data && ixData.data[0];
        
        const members = ((netixData && netixData.data) || []).map((m: any) => ({
          asn: m.asn, 
          name: m.name, 
          speed: m.speed, 
          ipaddr4: m.ipaddr4, 
          ipaddr6: m.ipaddr6, 
          policy: m.policy_general
        }));
        
        members.sort((a: any, b: any) => (b.speed || 0) - (a.speed || 0));
        
        return reply.status(200).send({ 
          ix_id: ixId, 
          ix_name: ix && ix.name, 
          ix_city: ix && ix.city, 
          members, 
          member_count: members.length 
        });
      } catch (e: any) {
        return reply.status(500).send({ error: e.message });
      }
    }
  );
}
