import type { BaseHandler } from '@stock-bot/handlers';
import type { DataIngestionServices } from '../../../types';
import { EOD_CONFIG } from '../shared';

interface FetchSymbolsInput {
  exchangeCode: string;
  delisted: boolean;
}


export async function scheduleFetchSymbols(
  this: BaseHandler<DataIngestionServices>
): Promise<{ success: boolean; jobsCreated: number }> {
  const logger = this.logger;
  
  try {
    logger.info('Starting symbol fetch job scheduling');
    
    // Get all exchanges from MongoDB
    const exchanges = await this.mongodb.collection('eodExchanges').find({}).toArray();
    
    if (!exchanges || exchanges.length === 0) {
      logger.warn('No exchanges found in database - run fetch-exchanges first');
      return { success: true, jobsCreated: 0 };
    }
    
    logger.info(`Found ${exchanges.length} exchanges to process`, {
      exchanges: exchanges.map(e => ({ code: e.Code, name: e.Name, country: e.Country }))
    });
    
    let jobsCreated = 0;
    
    // Create jobs for each exchange - both active and delisted symbols
    for (const exchange of exchanges) {
      const exchangeCode = exchange.Code;
      
      // Job for active symbols
      await this.scheduleOperation('fetch-symbols', {
        exchangeCode,
        delisted: false
      }, {
        attempts: 3,
        backoff: {
          type: 'exponential',
          delay: 5000
        }
      });
      jobsCreated++;
      
      // Job for delisted symbols
      await this.scheduleOperation('fetch-symbols', {
        exchangeCode,
        delisted: true
      }, {
        attempts: 3,
        backoff: {
          type: 'exponential',
          delay: 5000
        }
      });
      jobsCreated++;
    }
    
    logger.info(`Successfully created ${jobsCreated} symbol fetch jobs`);
    
    return {
      success: true,
      jobsCreated
    };
  } catch (error) {
    logger.error('Failed to schedule symbol fetch jobs', { error });
    throw error;
  }
}

export async function fetchSymbols(
  this: BaseHandler<DataIngestionServices>,
  input: FetchSymbolsInput
): Promise<{ success: boolean; count: number }> {
  const logger = this.logger;
  const { exchangeCode, delisted } = input;
  
  try {
    logger.info(`Fetching ${delisted ? 'delisted' : 'active'} symbols for ${exchangeCode}`);
    
    // Get API key from config
    const apiKey = EOD_CONFIG.API_TOKEN;
    if (!apiKey) {
      throw new Error('EOD API key not configured');
    }
    
    // Build URL with query parameters
    const url = new URL(`https://eodhd.com/api/exchange-symbol-list/${exchangeCode}`);
    url.searchParams.append('api_token', apiKey);
    url.searchParams.append('fmt', 'json');
    
    if (delisted) {
      url.searchParams.append('delisted', '1');
    }
    
    // Fetch symbols from EOD API using Bun fetch
    const response = await fetch(url.toString());
    
    if (!response.ok) {
      throw new Error(`EOD Symbols API returned ${response.status}: ${response.statusText}`);
    }
    
    const symbols = await response.json();
    
    if (!Array.isArray(symbols)) {
      throw new Error('Invalid response format from EOD API - expected array');
    }
    
    logger.info(`Fetched ${symbols.length} ${delisted ? 'delisted' : 'active'} symbols for ${exchangeCode}`);
    
    // Log some sample symbols
    if (symbols.length > 0) {
      logger.debug(`Sample ${delisted ? 'delisted' : 'active'} symbols for ${exchangeCode}:`, {
        count: symbols.length,
        samples: symbols.slice(0, 5).map(s => ({
          code: s.Code,
          name: s.Name,
          type: s.Type
        }))
      });
    }
    
    // Add metadata to each symbol
    const symbolsWithMetadata = symbols.map(symbol => ({
      ...symbol,
      Exchange: symbol.Exchange || exchangeCode, // Keep the original exchange (might be wrong)
      eodExchange: exchangeCode, // Store the correct exchange code used to fetch this symbol
      eodSearchCode: `${symbol.Code}.${exchangeCode}`, // Create unique search code like AAPL.US
      delisted: delisted,
    }));
    
    // Save to MongoDB - use Code as unique identifier along with exchange
    const result = await this.mongodb.batchUpsert(
      'eodSymbols', 
      symbolsWithMetadata, 
      ['Code', 'Exchange']
    );
    
    logger.info(`Successfully saved ${result.insertedCount} ${delisted ? 'delisted' : 'active'} symbols for ${exchangeCode}`);
    
    return {
      success: true,
      count: result.insertedCount
    };
  } catch (error) {
    logger.error('Failed to fetch or save symbols', { error, exchangeCode, delisted });
    throw error;
  }
}