import { fetch } from 'undici';
import { createModuleLogger } from './utils/logger.js';
import type { AppModules } from './wiring.js';

const log = createModuleLogger('telegram-poller');

const TELEGRAM_API_BASE = 'https://api.telegram.org/bot';
const POLL_TIMEOUT = 30; // seconds

interface PollerEntry {
  token: string;
  characterId: string;
  offset: number;
  running: boolean;
}

export class TelegramPoller {
  private pollers = new Map<string, PollerEntry>();
  private modules: AppModules;
  private active = false;
  private syncInterval?: ReturnType<typeof setInterval>;

  constructor(modules: AppModules) {
    this.modules = modules;
  }

  addBot(characterId: string, token: string): void {
    if (this.pollers.has(characterId)) return;
    const entry: PollerEntry = { token, characterId, offset: 0, running: false };
    this.pollers.set(characterId, entry);
    log.info({ characterId }, 'Bot added to poller');
    if (this.active) {
      this.pollLoop(entry);
    }
  }

  removeBot(characterId: string): void {
    const entry = this.pollers.get(characterId);
    if (entry) {
      entry.running = false;
      this.pollers.delete(characterId);
      log.info({ characterId }, 'Bot removed from poller');
    }
  }

  start(): void {
    this.active = true;
    // Initial sync
    this.syncBots();
    // Periodic sync every 10 seconds
    this.syncInterval = setInterval(() => this.syncBots(), 10000);
    for (const entry of this.pollers.values()) {
      if (!entry.running) {
        this.pollLoop(entry);
      }
    }
    log.info({ botCount: this.pollers.size }, 'Telegram poller started');
  }

  stop(): void {
    this.active = false;
    if (this.syncInterval) {
      clearInterval(this.syncInterval);
      this.syncInterval = undefined;
    }
    for (const entry of this.pollers.values()) {
      entry.running = false;
    }
    log.info('Telegram poller stopped');
  }

  async syncBots(): Promise<void> {
    const activeBots = this.modules.telegramManager.getActiveBots();
    for (const [characterId] of activeBots) {
      if (!this.pollers.has(characterId)) {
        const token = await this.modules.encryptedStore.getKey(`bot-token:${characterId}`);
        if (token) {
          this.addBot(characterId, token);
        }
      }
    }
    // Remove bots that are no longer active
    for (const [characterId] of this.pollers) {
      if (!activeBots.has(characterId)) {
        this.removeBot(characterId);
      }
    }
  }

  private async pollLoop(entry: PollerEntry): Promise<void> {
    entry.running = true;
    log.info({ characterId: entry.characterId }, 'Starting poll loop');

    // Delete webhook before starting polling (Telegram doesn't allow both)
    try {
      const deleteUrl = `${TELEGRAM_API_BASE}${entry.token}/deleteWebhook`;
      await fetch(deleteUrl, { method: 'POST' });
      log.info({ characterId: entry.characterId }, 'Webhook deleted for polling mode');
    } catch (err: any) {
      log.warn({ characterId: entry.characterId, error: err.message }, 'Failed to delete webhook');
    }

    while (entry.running && this.active) {
      try {
        const url = `${TELEGRAM_API_BASE}${entry.token}/getUpdates`;
        const response = await fetch(url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            offset: entry.offset,
            timeout: POLL_TIMEOUT,
            allowed_updates: ['message', 'pre_checkout_query'],
          }),
          signal: AbortSignal.timeout((POLL_TIMEOUT + 5) * 1000),
        });

        const data = await response.json() as { ok: boolean; result?: any[] };

        if (!data.ok || !data.result) {
          log.warn({ characterId: entry.characterId }, 'getUpdates returned not ok');
          await sleep(3000);
          continue;
        }

        for (const update of data.result) {
          entry.offset = update.update_id + 1;

          // Route through existing webhook handler
          const webhookHandler = this.modules.telegramManager.getWebhookHandler();
          try {
            await webhookHandler.handleTelegramWebhook(entry.token, update);
            log.debug({ characterId: entry.characterId, updateId: update.update_id }, 'Update processed');
          } catch (err: any) {
            log.error({ characterId: entry.characterId, updateId: update.update_id, error: err.message }, 'Failed to process update');
          }
        }

        if (data.result.length > 0) {
          log.info({ characterId: entry.characterId, count: data.result.length }, 'Processed updates');
        }
      } catch (err: any) {
        if (err.name === 'TimeoutError' || err.name === 'AbortError') {
          // Normal timeout, just continue
          continue;
        }
        log.error({ characterId: entry.characterId, error: err.message }, 'Poll error');
        await sleep(5000);
      }
    }

    entry.running = false;
    log.info({ characterId: entry.characterId }, 'Poll loop stopped');
  }
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

export function startTelegramPoller(modules: AppModules): TelegramPoller {
  const poller = new TelegramPoller(modules);
  return poller;
}
