import type { TradingViewHandler } from '../tradingview.handler';
import { TradingViewExchange } from '../shared/types';
import { TRADINGVIEW_CONFIG } from '../shared/config';

export async function fetchExchanges(handler: TradingViewHandler): Promise<TradingViewExchange[] | null> {
  const { logger, mongodb } = handler;
  
  if (!mongodb?.db) {
    logger.error('MongoDB not available');
    return null;
  }
  
  const db = mongodb.db;
  
  try {
    // 1. Fetch the HTML page
    const response = await fetch(TRADINGVIEW_CONFIG.DATA_COVERAGE_URL, {
      headers: {
        'User-Agent': TRADINGVIEW_CONFIG.USER_AGENT,
      },
    });
    
    logger.debug('Response status:', { 
      status: response.status, 
      statusText: response.statusText,
      url: response.url 
    });
    
    if (!response.ok) {
      throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
    }
    
    const html = await response.text();
    
    logger.info('Fetched HTML length:', { length: html.length });
    
    // Save HTML for debugging
    if (process.env.DEBUG_HTML) {
      const fs = await import('fs/promises');
      await fs.writeFile('/tmp/tradingview-data-coverage.html', html);
      logger.info('Saved HTML to /tmp/tradingview-data-coverage.html');
    }
    
    // 2. Parse HTML to extract exchange data from the table
    const exchanges: TradingViewExchange[] = [];
    
    // Match table rows containing exchange data
    const rowRegex = /<tr[^>]*class="row-qJcpoITA[^"]*"[^>]*>[\s\S]*?<\/tr>/g;
    const rows = html.match(rowRegex) || [];
    
    logger.debug('Found table rows:', { count: rows.length });
    
    for (const row of rows) {
      try {
        // Extract exchange ID
        const exchangeMatch = row.match(/alt="([^"]+)"/);
        const exchangeNameMatch = row.match(/<span[^>]*class="exchangeName-qJcpoITA"[^>]*>([^<]+)<\/span>/);
        const descriptionMatch = row.match(/<span[^>]*class="exchangeDescName-qJcpoITA"[^>]*>([^<]+)<\/span>/);
        const countryFlagMatch = row.match(/src="https:\/\/s3-symbol-logo\.tradingview\.com\/country\/([^.]+)\.svg"/);
        const countryNameMatch = row.match(/<img[^>]*class="[^"]*exchangeCountryFlag[^"]*"[^>]*\/>([^<]+)<\/span>/);
        
        // Extract data types from badges
        const badgeMatches = row.matchAll(/<span[^>]*class="badge-PlSmolIm[^"]*"[^>]*>[\s\S]*?<span[^>]*class="content-PlSmolIm"[^>]*>([^<]+)<\/span>/g);
        const dataTypes: string[] = [];
        for (const match of badgeMatches) {
          dataTypes.push(match[1].toLowerCase());
        }
        
        if (exchangeNameMatch && descriptionMatch && countryFlagMatch) {
          const exchange: TradingViewExchange = {
            exchange: descriptionMatch[1].toLowerCase().replace(/\s+/g, '_').replace(/[()]/g, ''),
            name: exchangeNameMatch[1],
            description: descriptionMatch[1],
            dataType: dataTypes,
            countryCode: countryFlagMatch[1].toUpperCase(),
            countryName: '', // Will be filled from alt text or other sources
          };
          
          // Try to extract country name
          if (countryNameMatch) {
            exchange.countryName = countryNameMatch[1].trim();
          } else if (exchangeMatch) {
            // Use alt text to extract country name
            const parts = exchangeMatch[1].split(' ');
            if (parts.length > 1) {
              exchange.countryName = parts[0];
            }
          }
          
          exchanges.push(exchange);
        }
      } catch (e) {
        logger.debug('Failed to parse row', { error: e });
      }
    }
    
    if (exchanges.length === 0) {
      throw new Error('No exchanges found in HTML');
    }
    
    logger.info('Extracted exchanges from HTML', { count: exchanges.length });
    
    // Batch update tvExchanges collection
    try {
      const batchOps = exchanges.map(exchange => ({
        updateOne: {
          filter: { exchange: exchange.exchange },
          update: {
            $set: {
              ...exchange,
              updated_at: new Date(),
            },
            $setOnInsert: {
              created_at: new Date(),
            },
          },
          upsert: true,
        },
      }));
      
      if (batchOps.length > 0) {
        await db.collection('tvExchanges').bulkWrite(batchOps);
      }
      
      logger.info('TradingView exchanges saved to MongoDB');
    } catch (dbError) {
      logger.warn('Failed to save exchanges to MongoDB', { error: dbError });
    }
    
    logger.info('TradingView exchanges fetched', {
      count: exchanges.length,
      byType: groupExchangesByType(exchanges),
    });
    
    return exchanges;
  } catch (error) {
    logger.error('Failed to fetch TradingView exchanges', { 
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
    });
    return null;
  }
}

function groupExchangesByType(exchanges: TradingViewExchange[]) {
  const groups: Record<string, number> = {};
  
  for (const exchange of exchanges) {
    for (const type of exchange.dataType) {
      groups[type] = (groups[type] || 0) + 1;
    }
  }
  
  return groups;
}