/**
 * QM Symbol Actions - Symbol search and spider operations
 */

import type { ExecutionContext } from '@stock-bot/handlers';
import type { QMHandler } from '../qm.handler';
import { QM_CONFIG, QM_SESSION_IDS } from '../shared/config';
import { QMSessionManager } from '../shared/session-manager';
import type { Exchange, SymbolSpiderJob } from '../shared/types';

/**
 * Spider search for symbols - recursively searches QM API
 * Root job (no prefix) creates A-Z jobs
 * Each job searches its prefix and creates child jobs if needed
 */
export async function spiderSymbol(
  this: QMHandler,
  input: SymbolSpiderJob,
  _context: ExecutionContext
): Promise<{
  message: string;
  symbolsFound?: number;
  jobsCreated?: number;
}> {
  const { prefix, depth = 0, maxDepth = 4 } = input || {};

  this.logger.info(`Spider symbol search ${prefix}`, { prefix, depth, maxDepth });

  if (!prefix) {
    // Root job - create A-Z jobs
    let jobsCreated = 0;
    for (let i = 0; i < 26; i++) {
      const letter = String.fromCharCode(65 + i); // A-Z
      await this.scheduleOperation('spider-symbols', {
        prefix: letter,
        depth: 1,
        source: 'qm',
        maxDepth
      }, {
        priority: 5
      });
      jobsCreated++;
    }

    this.logger.info('Created root spider jobs', { jobsCreated });
    return { 
      message: `Queued ${jobsCreated} root jobs (A-Z)`, 
      jobsCreated 
    };
  }

  try {
    // Search current prefix
    const symbols = await searchSymbols.call(this, { query: prefix });
    
    if (!symbols || symbols.length === 0) {
      this.logger.debug('No symbols found for prefix', { prefix });
      return { 
        message: `No symbols found for prefix: ${prefix}`,
        symbolsFound: 0 
      };
    }

    await this.mongodb?.batchUpsert('qmSymbols', symbols, ['qmSearchCode']);
    
    this.logger.info(`Stored symbols from spider search ${prefix} - ${symbols.length}`, { 
      prefix, 
      count: symbols.length 
    });

    // Extract and store unique exchanges
    const exchanges: Exchange[] = [];
    for (const symbol of symbols) {
      if (symbol.exchange && !exchanges.some(ex => ex.exchange === symbol.exchange)) {
        exchanges.push({
          exchange: symbol.exchange,
          exchangeName: symbol.exchangeName || '',
          countryCode: symbol.countryCode || '',
          source: 'qm',
        });
      }
    }

    if (exchanges.length > 0) {
      await this.mongodb?.batchUpsert('qmExchanges', exchanges, ['exchange']);
      this.logger.debug('Stored exchanges from spider search', { 
        count: exchanges.length 
      });
    }

    // If not at max depth and we found symbols, create child jobs
    if (depth < maxDepth && symbols.length > 0) {
      let jobsCreated = 0;
      
      // Only create child jobs if we found a significant number of symbols
      // This prevents excessive branching on sparse results
      if (symbols.length >= 50) {
        for (let i = 0; i < 26; i++) {
          const nextPrefix = prefix + String.fromCharCode(65 + i);
          await this.scheduleOperation('spider-symbols', {
            prefix: nextPrefix,
            depth: depth + 1,
            source: 'qm',
            maxDepth
          }, {
            priority: Math.max(1, 5 - depth)
          });
          jobsCreated++;
        }
      }

      return { 
        message: `Found ${symbols.length} symbols for ${prefix}, queued ${jobsCreated} child jobs`,
        symbolsFound: symbols.length,
        jobsCreated 
      };
    }

    return { 
      message: `Found ${symbols.length} symbols for ${prefix} (at max depth or too few results)`,
      symbolsFound: symbols.length 
    };

  } catch (error) {
    this.logger.error(`Spider search failed ${prefix}`, { prefix, error });
    return {
      message: `Spider search failed for prefix: ${prefix}`,
      symbolsFound: 0
    };
  }
}

/**
 * Search QM symbols API directly
 */
export async function searchSymbols(
  this: QMHandler,
  input: { query: string },
  _context?: ExecutionContext
): Promise<any[]> {
  const { query } = input;
  
  this.logger.debug('Searching QM symbols', { query });

  const sessionManager = QMSessionManager.getInstance();
  await sessionManager.initialize(this.cache, this.logger);

  // Get a session
  const sessionId = QM_SESSION_IDS.LOOKUP;
  const session = await sessionManager.getSession(sessionId);
  
  if (!session || !session.uuid) {
    throw new Error(`No active session found for QM LOOKUP`);
  }

  try {
    // Build API request
    const searchParams = new URLSearchParams({
      marketType: 'equity',
      pathName: '/demo/portal/company-summary.php',
      q: query,
      qmodTool: 'SmartSymbolLookup',
      searchType: 'symbol',
      showFree: 'false',
      showHisa: 'false',
      webmasterId: '500'
    });
    
    const apiUrl = `${QM_CONFIG.LOOKUP_URL}?${searchParams.toString()}`;

    const response = await fetch(apiUrl, {
      method: 'GET',
      headers: session.headers,
      proxy: session.proxy,
    });

    if (!response.ok) {
      throw new Error(`QM API request failed: ${response.status} ${response.statusText}`);
    }

    const symbols = await response.json();
    
    // Update session success stats
    await sessionManager.incrementSuccessfulCalls(sessionId, session.uuid);

    // Process symbol data
    const processedSymbols = Array.isArray(symbols) ? symbols.map((symbol: any) => {
      const { exchangeCode, exchangeShortName, ...rest } = symbol;
      return {
        ...rest,
        exchange: exchangeCode,
        exchangeName: exchangeShortName,
        qmSearchCode: symbol.symbol,
        symbol: (symbol.symbol as string)?.split(':')[0],
      };
    }) : [];

    this.logger.debug('QM API returned symbols ${query} - ${processedSymbols.length}', { 
      query,
      count: processedSymbols.length 
    });

    return processedSymbols;

  } catch (error) {
    // Update session failure stats
    if (session.uuid) {
      await sessionManager.incrementFailedCalls(sessionId, session.uuid);
    }

    this.logger.error('Error searching QM symbols', { 
      query,
      error: error instanceof Error ? error.message : 'Unknown error'
    });
    
    throw error;
  }
}