import { FastifyPluginAsync } from 'fastify';
import { WebSocket } from 'ws';
import { PriceRepository } from '../../database/repository';

interface WebSocketMessage {
  type: string;
  data?: any;
}

interface WebSocketConnection {
  socket: WebSocket;
}

const clients = new Set<WebSocketConnection>();
const repository = new PriceRepository();

export const websocketRoutes: FastifyPluginAsync = async (server) => {
  server.log.info('WebSocket route registered at /ws');
  
  server.get('/ws', { websocket: true }, (socket: any, request: any) => {
    server.log.info('WebSocket client connected');
    console.log('✓ WebSocket client connected');
    
    const connection = { socket };
    clients.add(connection);

    // Send connection confirmation
    socket.send(JSON.stringify({
      type: 'connection_status',
      data: { connected: true, message: 'Connected to rmtPocketWatcher' }
    }));

    // Handle incoming messages
    socket.on('message', async (message: Buffer) => {
      try {
        const parsed: WebSocketMessage = JSON.parse(message.toString());
        
        if (parsed.type === 'subscribe' && parsed.data?.channel === 'price_updates') {
          // Send latest price data on subscription
          const latestPrices = await repository.getLatestPrices();
          
          if (latestPrices.length > 0) {
            const lowestPrice = latestPrices.reduce((min: any, p: any) => 
              Number(p.usdPerMillion) < Number(min.usdPerMillion) ? p : min
            );

            socket.send(JSON.stringify({
              type: 'price_update',
              data: {
                timestamp: new Date(),
                lowestPrice: Number(lowestPrice.usdPerMillion),
                platform: lowestPrice.vendor,
                sellerName: lowestPrice.sellerName,
                allPrices: latestPrices.map((p: any) => ({
                  id: p.id,
                  platform: p.vendor,
                  sellerName: p.sellerName,
                  pricePerMillion: Number(p.usdPerMillion),
                  timestamp: p.timestamp,
                  url: p.url
                }))
              }
            }));
          }
        } else if (parsed.type === 'get_history') {
          // Handle historical data request
          const { range } = parsed.data || {};
          const now = new Date();
          let from = new Date();

          switch (range) {
            case '6h':
              from = new Date(now.getTime() - 6 * 60 * 60 * 1000);
              break;
            case '24h':
              from = new Date(now.getTime() - 24 * 60 * 60 * 1000);
              break;
            case '3d':
              from = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);
              break;
            case '7d':
              from = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
              break;
            case '1mo':
              from = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
              break;
            case 'ytd':
              from = new Date(now.getFullYear(), 0, 1);
              break;
            default:
              from = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
          }

          const history = await repository.getPriceHistory(from, now);
          
          const payload = {
            type: 'history_data',
            data: {
              range,
              from,
              to: now,
              prices: history.map((p: any) => ({
                id: p.id,
                platform: p.vendor,
                sellerName: p.sellerName,
                pricePerMillion: Number(p.usdPerMillion),
                timestamp: p.timestamp,
                url: p.url
              }))
            }
          };
          
          server.log.info(`Sending history data: ${payload.data.prices.length} prices for range ${range}`);
          socket.send(JSON.stringify(payload));
        }
      } catch (error: any) {
        server.log.error({ error }, 'Error handling WebSocket message');
        socket.send(JSON.stringify({
          type: 'error',
          data: 'Invalid message format'
        }));
      }
    });

    socket.on('close', () => {
      server.log.info('WebSocket client disconnected');
      clients.delete(connection);
    });

    socket.on('error', (error: any) => {
      server.log.error({ error }, 'WebSocket error');
      clients.delete(connection);
    });
  });
};

// Broadcast price updates to all connected clients
export function broadcastPriceUpdate(data: any): void {
  const message = JSON.stringify({
    type: 'price_update',
    data
  });

  clients.forEach((connection) => {
    try {
      if (connection.socket.readyState === 1) { // OPEN
        connection.socket.send(message);
      }
    } catch (error) {
      console.error('Error broadcasting to client:', error);
    }
  });
}
