import type { IServiceContainer } from '@stock-bot/handlers';
import { getLogger } from '@stock-bot/logger';
import type { MasterExchange } from '@stock-bot/mongodb';
import type { JobPayload } from '../../../types/job-payloads';

const logger = getLogger('sync-ib-exchanges');

interface IBExchange {
  id?: string;
  _id?: any;
  name?: string;
  code?: string;
  country_code?: string;
  currency?: string;
}

export async function syncIBExchanges(
  payload: JobPayload,
  container: IServiceContainer
): Promise<{ syncedCount: number; totalExchanges: number }> {
  logger.info('Syncing IB exchanges from database...');

  try {
    const mongoClient = container.mongodb;
    const db = mongoClient.getDatabase();

    // Filter by country code US and CA
    const ibExchanges = await db
      .collection<IBExchange>('ibExchanges')
      .find({
        country_code: { $in: ['US', 'CA'] },
      })
      .toArray();

    logger.info('Found IB exchanges in database', { count: ibExchanges.length });

    let syncedCount = 0;

    for (const exchange of ibExchanges) {
      try {
        await createOrUpdateMasterExchange(exchange, container);
        syncedCount++;

        logger.debug('Synced IB exchange', {
          ibId: exchange.id,
          country: exchange.country_code,
        });
      } catch (error) {
        logger.error('Failed to sync IB exchange', { exchange: exchange.id, error });
      }
    }

    logger.info('IB exchange sync completed', {
      syncedCount,
      totalExchanges: ibExchanges.length,
    });

    return { syncedCount, totalExchanges: ibExchanges.length };
  } catch (error) {
    logger.error('Failed to fetch IB exchanges from database', { error });
    return { syncedCount: 0, totalExchanges: 0 };
  }
}

/**
 * Create or update master exchange record 1:1 from IB exchange
 */
async function createOrUpdateMasterExchange(
  ibExchange: IBExchange,
  container: IServiceContainer
): Promise<void> {
  const mongoClient = container.mongodb;
  const db = mongoClient.getDatabase();
  const collection = db.collection<MasterExchange>('masterExchanges');

  const masterExchangeId = generateMasterExchangeId(ibExchange);
  const now = new Date();

  // Check if master exchange already exists
  const existing = await collection.findOne({ masterExchangeId });

  if (existing) {
    // Update existing record
    await collection.updateOne(
      { masterExchangeId },
      {
        $set: {
          officialName: ibExchange.name || `Exchange ${ibExchange.id}`,
          country: ibExchange.country_code || 'UNKNOWN',
          currency: ibExchange.currency || 'USD',
          timezone: inferTimezone(ibExchange),
          updated_at: now,
        },
      }
    );

    logger.debug('Updated existing master exchange', { masterExchangeId });
  } else {
    // Create new master exchange
    const masterExchange: MasterExchange = {
      masterExchangeId,
      shortName: masterExchangeId, // Set shortName to masterExchangeId on creation
      officialName: ibExchange.name || `Exchange ${ibExchange.id}`,
      country: ibExchange.country_code || 'UNKNOWN',
      currency: ibExchange.currency || 'USD',
      timezone: inferTimezone(ibExchange),
      active: false, // Set active to false only on creation

      sourceMappings: {
        ib: {
          id: ibExchange.id || ibExchange._id?.toString() || 'unknown',
          name: ibExchange.name || `Exchange ${ibExchange.id}`,
          code: ibExchange.code || ibExchange.id || '',
          aliases: generateAliases(ibExchange),
          lastUpdated: now,
        },
      },

      confidence: 1.0, // High confidence for direct IB mapping
      verified: true, // Mark as verified since it's direct from IB

      // DocumentBase fields
      source: 'ib-exchange-sync',
      created_at: now,
      updated_at: now,
    };

    await collection.insertOne(masterExchange);
    logger.debug('Created new master exchange', { masterExchangeId });
  }
}

/**
 * Generate master exchange ID from IB exchange
 */
function generateMasterExchangeId(ibExchange: IBExchange): string {
  // Use code if available, otherwise use ID, otherwise generate from name
  if (ibExchange.code) {
    return ibExchange.code.toUpperCase().replace(/[^A-Z0-9]/g, '');
  }

  if (ibExchange.id) {
    return ibExchange.id.toUpperCase().replace(/[^A-Z0-9]/g, '');
  }

  if (ibExchange.name) {
    return ibExchange.name
      .toUpperCase()
      .split(' ')
      .slice(0, 2)
      .join('_')
      .replace(/[^A-Z0-9_]/g, '');
  }

  return 'UNKNOWN_EXCHANGE';
}

/**
 * Generate aliases for the exchange
 */
function generateAliases(ibExchange: IBExchange): string[] {
  const aliases: string[] = [];

  if (ibExchange.name && ibExchange.name.includes(' ')) {
    // Add abbreviated version
    aliases.push(
      ibExchange.name
        .split(' ')
        .map(w => w[0])
        .join('')
        .toUpperCase()
    );
  }

  if (ibExchange.code) {
    aliases.push(ibExchange.code.toUpperCase());
  }

  return aliases;
}

/**
 * Infer timezone from exchange name/location
 */
function inferTimezone(ibExchange: IBExchange): string {
  if (!ibExchange.name) {
    return 'UTC';
  }

  const name = ibExchange.name.toUpperCase();

  if (name.includes('NEW YORK') || name.includes('NYSE') || name.includes('NASDAQ')) {
    return 'America/New_York';
  }
  if (name.includes('LONDON')) {
    return 'Europe/London';
  }
  if (name.includes('TOKYO')) {
    return 'Asia/Tokyo';
  }
  if (name.includes('SHANGHAI')) {
    return 'Asia/Shanghai';
  }
  if (name.includes('TORONTO')) {
    return 'America/Toronto';
  }
  if (name.includes('FRANKFURT')) {
    return 'Europe/Berlin';
  }

  return 'UTC'; // Default
}
