/**
 * QM Symbol Deduplication and Exchange Statistics
 * - Updates exchange statistics (symbol count, market cap)
 * - Assigns priority to exchanges
 * - Marks active/inactive symbols to eliminate duplicates
 */

import type { ExecutionContext } from '@stock-bot/handlers';
import type { QMHandler } from '../qm.handler';
import type { ExchangeStats } from '../shared/types';

/**
 * Exchange priority mapping
 */
const EXCHANGE_PRIORITIES: Record<string, number> = {
  // Major US exchanges
  'NYSE': 10,
  'NASDAQ': 10,
  'NYSE American': 9,
  
  // Other US exchanges
  'EDGX': 5,
  'BZX': 5,
  'ARCA': 5,
  
  // Canadian main exchanges
  'TSX': 8,
  'TSXV': 8,
  'CSE': 7,
  
  // Canadian quote exchanges
  'CCQ TSX': 3,
  'CCQ TSXV': 3,
  
  // Default for others
  'default': 1
};

/**
 * Update exchange statistics
 */
export async function updateExchangeStats(
  this: QMHandler,
  _input: any,
  _context: ExecutionContext
): Promise<{ message: string; exchangesUpdated: number }> {
  this.logger.info('Updating exchange statistics');

  try {
    // Get all exchanges
    const exchanges = await this.mongodb.find('qmExchanges', {});
    
    if (!exchanges || exchanges.length === 0) {
      return { message: 'No exchanges found', exchangesUpdated: 0 };
    }

    // Calculate stats for each exchange
    const bulkOps = [];
    
    for (const exchange of exchanges) {
      // Get symbol statistics for this exchange
      const stats = await this.mongodb.aggregate('qmSymbols', [
        { $match: { exchange: exchange.exchange } },
        {
          $group: {
            _id: null,
            symbolCount: { $sum: 1 },
            totalMarketCap: { $sum: { $ifNull: ['$marketCap', 0] } },
            avgMarketCap: { $avg: { $ifNull: ['$marketCap', 0] } }
          }
        }
      ]);

      const exchangeStats: ExchangeStats = stats[0] || {
        symbolCount: 0,
        totalMarketCap: 0,
        avgMarketCap: 0
      };

      // Get priority for this exchange
      const priority = EXCHANGE_PRIORITIES[exchange.exchange] || EXCHANGE_PRIORITIES.default;

      // Prepare update
      bulkOps.push({
        updateOne: {
          filter: { exchange: exchange.exchange },
          update: {
            $set: {
              'stats.symbolCount': exchangeStats.symbolCount,
              'stats.totalMarketCap': exchangeStats.totalMarketCap,
              'stats.avgMarketCap': Math.round(exchangeStats.avgMarketCap),
              priority,
              updated_at: new Date()
            }
          }
        }
      });
    }

    // Execute bulk update
    if (bulkOps.length > 0) {
      const collection = this.mongodb.collection('qmExchanges');
      await collection.bulkWrite(bulkOps);
    }


    this.logger.info(`Updated statistics for ${exchanges.length} exchanges`);
    return { 
      message: `Updated statistics for ${exchanges.length} exchanges`, 
      exchangesUpdated: exchanges.length 
    };

  } catch (error) {
    this.logger.error('Failed to update exchange statistics', { error });
    throw error;
  }
}

/**
 * Deduplicate symbols based on country and exchange rules
 */
export async function deduplicateSymbols(
  this: QMHandler,
  _input: any,
  _context: ExecutionContext
): Promise<{ message: string; symbolsProcessed: number; deactivated: number }> {
  this.logger.info('Starting symbol deduplication');

  try {
    // Get all unique symbol names with their documents
    const symbolGroups = await this.mongodb.aggregate('qmSymbols', [
      {
        $group: {
          _id: '$symbol',
          symbols: {
            $push: {
              qmSearchCode: '$qmSearchCode',
              exchange: '$exchange',
              countryCode: '$countryCode',
              marketCap: { $ifNull: ['$marketCap', 0] },
              _id: '$_id'
            }
          }
        }
      }
    ]);

    let totalProcessed = 0;
    let totalDeactivated = 0;
    const bulkOps = [];

    // Get exchange priorities for sorting
    const exchangePriorities = await this.mongodb.find('qmExchanges', {}, {
      projection: { exchange: 1, priority: 1 }
    });
    const priorityMap = new Map(exchangePriorities.map(e => [e.exchange, e.priority || 1]));

    for (const group of symbolGroups) {
      const symbol = group._id;
      const documents = group.symbols;

      // Group by country
      const byCountry = new Map<string, any[]>();
      for (const doc of documents) {
        const country = doc.countryCode || 'UNKNOWN';
        if (!byCountry.has(country)) {
          byCountry.set(country, []);
        }
        byCountry.get(country)!.push(doc);
      }

      // Process each country separately
      for (const [country, countryDocs] of byCountry) {
        if (countryDocs.length === 1) {
          // Only one symbol in this country, mark as active
          bulkOps.push({
            updateOne: {
              filter: { _id: countryDocs[0]._id },
              update: { $set: { active: true } }
            }
          });
          totalProcessed++;
          continue;
        }

        // Multiple symbols in same country - need to choose one
        let activeDoc = null;

        if (country === 'US') {
          // For US, prefer where qmSearchCode === symbol
          activeDoc = countryDocs.find(doc => doc.qmSearchCode === symbol);
        } else {
          // For non-US, prefer symbol:COUNTRYCODE format
          const expectedFormat = `${symbol}:${country}`;
          activeDoc = countryDocs.find(doc => doc.qmSearchCode === expectedFormat);
        }

        // If no preferred format found, use highest priority exchange
        if (!activeDoc) {
          // Sort by exchange priority (desc) and market cap (desc)
          countryDocs.sort((a, b) => {
            const priorityA = priorityMap.get(a.exchange) || 1;
            const priorityB = priorityMap.get(b.exchange) || 1;
            if (priorityA !== priorityB) { return priorityB - priorityA }
            return (b.marketCap || 0) - (a.marketCap || 0);
          });
          activeDoc = countryDocs[0];
        }

        // Mark active and inactive documents
        for (const doc of countryDocs) {
          const isActive = doc._id.equals(activeDoc._id);
          bulkOps.push({
            updateOne: {
              filter: { _id: doc._id },
              update: { $set: { active: isActive } }
            }
          });
          totalProcessed++;
          if (!isActive) { totalDeactivated++ }
        }
      }
    }

    // Execute bulk update
    if (bulkOps.length > 0) {
      const collection = this.mongodb.collection('qmSymbols');
      await collection.bulkWrite(bulkOps, { ordered: false });
    }


    this.logger.info(`Deduplication complete: processed ${totalProcessed} symbols, deactivated ${totalDeactivated}`);
    return {
      message: `Processed ${totalProcessed} symbols, deactivated ${totalDeactivated} duplicates`,
      symbolsProcessed: totalProcessed,
      deactivated: totalDeactivated
    };

  } catch (error) {
    this.logger.error('Failed to deduplicate symbols', { error });
    throw error;
  }
}

/**
 * Run both exchange stats and symbol deduplication
 */
export async function updateExchangeStatsAndDeduplicate(
  this: QMHandler,
  input: any,
  context: ExecutionContext
): Promise<{ message: string }> {
  this.logger.info('Running exchange stats update and symbol deduplication');

  try {
    // First update exchange stats
    const statsResult = await updateExchangeStats.call(this, input, context);
    
    // Then deduplicate symbols
    const dedupResult = await deduplicateSymbols.call(this, input, context);

    return {
      message: `${statsResult.message}. ${dedupResult.message}`
    };
  } catch (error) {
    this.logger.error('Failed to update stats and deduplicate', { error });
    throw error;
  }
}