import { getRandomUserAgent } from '@stock-bot/utils';
import type { CeoHandler } from '../ceo.handler';

export async function getPosts(this: CeoHandler, payload: any, _context: any): Promise<unknown> {
  const { ceoId, symbol, timestamp, finished } = payload;
  const proxy = this.proxy?.getProxy();
  if (!proxy) {
    this.logger.warn('No proxy available for processing individual CEO symbol');
    return;
  }

  this.logger.debug('Processing individual CEO symbol', {
    ceoId,
    timestamp,
  });
  try {
    // Fetch detailed information for the individual symbol
    const response = await this.http.get(
      `https://api.ceo.ca/api/get_spiels?channel=${ceoId}&load_more=top` +
        (timestamp ? `&until=${timestamp}` : ''),
      {
        proxy: proxy,
        headers: {
          'User-Agent': getRandomUserAgent(),
        },
      }
    );

    if (!response.ok) {
      this.logger.debug(`Response status: ${response.status}`);
      throw new Error(`Failed to fetch details for ceoId ${ceoId}: ${response.statusText}`);
    }

    const data = await response.json();

    const spielCount = data.spiels.length;
    if (spielCount === 0) {
      this.logger.warn(`No spiels found for ceoId ${ceoId}`);

      if (!timestamp) {
        // First call returned no posts - mark as finished with current time
        await this.mongodb.updateMany(
          'ceoSymbols',
          { ceoId },
          {
            $set: {
              finished: true,
              newestPostTimestamp: Date.now(),
            },
          }
        );
      }
      return null; // No data to process
    }

    // Extract timestamps clearly
    const oldestPostInBatch = data.spiels[0]?.timestamp;
    const newestPostInBatch = data.spiels[data.spiels.length - 1]?.timestamp;
    const posts = data.spiels.map((spiel: any) => ({
      ceoId,
      spiel: spiel.spiel,
      spielReplyToId: spiel.spiel_reply_to_id,
      spielReplyTo: spiel.spiel_reply_to,
      spielReplyToName: spiel.spiel_reply_to_name,
      spielReplyToEdited: spiel.spiel_reply_to_edited,
      userId: spiel.user_id,
      name: spiel.name,
      timestamp: spiel.timestamp,
      spielId: spiel.spiel_id,
      color: spiel.color,
      parentId: spiel.parent_id,
      publicId: spiel.public_id,
      parentChannel: spiel.parent_channel,
      parentTimestamp: spiel.parent_timestamp,
      votes: spiel.votes,
      editable: spiel.editable,
      edited: spiel.edited,
      featured: spiel.featured,
      verified: spiel.verified,
      fake: spiel.fake,
      bot: spiel.bot,
      voted: spiel.voted,
      flagged: spiel.flagged,
      ownSpiel: spiel.own_spiel,
      score: spiel.score,
      savedId: spiel.saved_id,
      savedTimestamp: spiel.saved_timestamp,
      poll: spiel.poll,
      votedInPoll: spiel.voted_in_poll,
    }));

    // Handle based on collection state
    if (!finished) {
      // INITIAL COLLECTION MODE
      // Insert all posts - no duplicate checking needed on initial collection
      await this.mongodb.batchUpsert('ceoPosts', posts, ['spielId']);

      // Update newest timestamp on first call only
      if (!timestamp) {
        await this.mongodb.updateMany(
          'ceoSymbols',
          { ceoId },
          { $set: { newestPostTimestamp: newestPostInBatch } }
        );
      }

      this.logger.info(`Initial collection: fetched ${spielCount} spiels for ${ceoId}`);

      // Continue paginating backwards through history
      await this.scheduleOperation(
        'get-posts',
        {
          ceoId: ceoId,
          symbol: symbol,
          timestamp: oldestPostInBatch,
          finished: false,
        },
        { priority: 0 }
      );
    } else {
      // UPDATE COLLECTION MODE (finished=true)
      // Get the last known newest post
      const symbolData = await this.mongodb.findOne('ceoSymbols', { ceoId });
      const lastKnownNewestTimestamp =
        symbolData?.newestPostTimestamp || symbolData?.lastSpielTime || 0;

      // Filter to only posts newer than what we've seen
      const newPosts = posts.filter((p: any) => p.timestamp > lastKnownNewestTimestamp);

      if (newPosts.length === 0) {
        this.logger.info(`No new posts for ${ceoId}, all ${posts.length} posts already collected`);
        return { ceoId, spielCount: 0, timestamp };
      }

      // Insert new posts
      await this.mongodb.batchUpsert('ceoPosts', newPosts, ['spielId']);

      // Update to the newest timestamp we've now seen
      await this.mongodb.updateMany(
        'ceoSymbols',
        { ceoId },
        { $set: { newestPostTimestamp: newestPostInBatch } }
      );

      this.logger.info(`Update collection: collected ${newPosts.length} new posts for ${ceoId}`);

      // If all posts in batch were new, there might be more in the gap
      // Continue paginating until we hit posts we've already seen
      if (newPosts.length === posts.length && oldestPostInBatch > lastKnownNewestTimestamp) {
        this.logger.info(`All posts were new, checking for more in the gap`);
        await this.scheduleOperation(
          'get-posts',
          {
            ceoId: ceoId,
            symbol: symbol,
            timestamp: oldestPostInBatch,
            finished: true,
          },
          { priority: 0 }
        );
      }
    }

    // If timestamp is not provided, run the short positions update
    if (!timestamp) {
      await this.scheduleOperation('get-shorts', {
        symbol: symbol,
      });
    }

    this.logger.info(`Successfully processed channel ${ceoId}`);

    return { ceoId, spielCount, timestamp };
  } catch (error: any) {
    this.logger.error(`Failed to process individual symbol ${symbol}`, {
      error,
      ceoId,
      timestamp,
    });
    throw new Error(`Failed to process individual symbol ${symbol}`, error.message);
  }
}
