import { createModuleLogger } from '../../utils/index.js';
import type { TelegramUpdate, TelegramMessage, PreCheckoutQuery, SuccessfulPayment } from '../../types/telegram.js';
import type { KIETaskResponse } from '../../types/api.js';

const log = createModuleLogger('webhook-handler');

export type MessageHandler = (botToken: string, message: TelegramMessage) => void | Promise<void>;
export type PreCheckoutQueryHandler = (botToken: string, query: PreCheckoutQuery) => void | Promise<void>;
export type SuccessfulPaymentHandler = (botToken: string, payment: SuccessfulPayment, message: TelegramMessage) => void | Promise<void>;
export type KIECompleteHandler = (response: KIETaskResponse) => void | Promise<void>;

export class WebhookHandler {
  private registeredTokens: Set<string>;
  private messageHandlers: Map<string, MessageHandler> = new Map();
  private preCheckoutHandlers: Map<string, PreCheckoutQueryHandler> = new Map();
  private successfulPaymentHandlers: Map<string, SuccessfulPaymentHandler> = new Map();
  private kieCompleteHandlers: KIECompleteHandler[] = [];

  constructor(registeredTokens: Map<string, string> | Set<string> | string[]) {
    if (registeredTokens instanceof Map) {
      this.registeredTokens = new Set(registeredTokens.keys());
    } else if (registeredTokens instanceof Set) {
      this.registeredTokens = new Set(registeredTokens);
    } else {
      this.registeredTokens = new Set(registeredTokens);
    }
    log.info({ tokenCount: this.registeredTokens.size }, 'WebhookHandler initialized');
  }

  validateToken(botToken: string): boolean {
    return this.registeredTokens.has(botToken);
  }

  registerToken(botToken: string): void {
    this.registeredTokens.add(botToken);
    log.info('Bot token registered');
  }

  unregisterToken(botToken: string): void {
    this.registeredTokens.delete(botToken);
    this.messageHandlers.delete(botToken);
    this.preCheckoutHandlers.delete(botToken);
    this.successfulPaymentHandlers.delete(botToken);
    log.info('Bot token unregistered');
  }

  onMessage(botToken: string, handler: MessageHandler): void {
    this.messageHandlers.set(botToken, handler);
  }

  onPreCheckoutQuery(botToken: string, handler: PreCheckoutQueryHandler): void {
    this.preCheckoutHandlers.set(botToken, handler);
  }

  onSuccessfulPayment(botToken: string, handler: SuccessfulPaymentHandler): void {
    this.successfulPaymentHandlers.set(botToken, handler);
  }

  onKIEComplete(handler: KIECompleteHandler): void {
    this.kieCompleteHandlers.push(handler);
  }

  async handleTelegramWebhook(botToken: string, update: TelegramUpdate): Promise<{ ok: boolean; error?: string }> {
    if (!botToken || typeof botToken !== 'string') {
      log.warn('Missing or invalid bot token in webhook request');
      return { ok: false, error: 'Missing bot token' };
    }

    if (!this.validateToken(botToken)) {
      log.warn({ botToken: botToken.slice(-4) }, 'Invalid bot token in webhook request');
      return { ok: false, error: 'Invalid bot token' };
    }

    if (!update || typeof update.update_id !== 'number') {
      log.warn('Invalid webhook payload: missing update_id');
      return { ok: false, error: 'Invalid payload' };
    }

    try {
      if (update.pre_checkout_query) {
        await this.handlePreCheckoutQuery(botToken, update.pre_checkout_query);
      }

      if (update.message) {
        if (update.message.successful_payment) {
          await this.handleSuccessfulPayment(botToken, update.message.successful_payment, update.message);
        } else {
          await this.handleMessage(botToken, update.message);
        }
      }

      return { ok: true };
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      log.error({ err, updateId: update.update_id }, 'Error processing Telegram webhook');
      return { ok: false, error: errorMessage };
    }
  }

  async handleKIEWebhook(payload: unknown): Promise<{ ok: boolean; error?: string }> {
    if (!payload || typeof payload !== 'object') {
      log.warn('Invalid KIE webhook payload');
      return { ok: false, error: 'Invalid payload' };
    }

    const response = payload as Record<string, unknown>;

    if (!response.taskId || typeof response.taskId !== 'string') {
      log.warn('KIE webhook payload missing taskId');
      return { ok: false, error: 'Missing taskId' };
    }

    if (!response.status || typeof response.status !== 'string') {
      log.warn('KIE webhook payload missing status');
      return { ok: false, error: 'Missing status' };
    }

    const validStatuses = ['pending', 'processing', 'completed', 'failed'];
    if (!validStatuses.includes(response.status as string)) {
      log.warn({ status: response.status }, 'KIE webhook payload has invalid status');
      return { ok: false, error: 'Invalid status' };
    }

    const kieResponse: KIETaskResponse = {
      taskId: response.taskId as string,
      status: response.status as KIETaskResponse['status'],
      resultUrl: typeof response.resultUrl === 'string' ? response.resultUrl : undefined,
      error: typeof response.error === 'string' ? response.error : undefined,
    };

    try {
      for (const handler of this.kieCompleteHandlers) {
        await handler(kieResponse);
      }
      log.info({ taskId: kieResponse.taskId, status: kieResponse.status }, 'KIE webhook processed');
      return { ok: true };
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      log.error({ err, taskId: kieResponse.taskId }, 'Error processing KIE webhook');
      return { ok: false, error: errorMessage };
    }
  }

  private async handleMessage(botToken: string, message: TelegramMessage): Promise<void> {
    const handler = this.messageHandlers.get(botToken);
    if (handler) {
      await handler(botToken, message);
      log.debug({ chatId: message.chat.id, messageId: message.message_id }, 'Message handled');
    } else {
      log.debug({ chatId: message.chat.id }, 'No message handler registered for this bot');
    }
  }

  private async handlePreCheckoutQuery(botToken: string, query: PreCheckoutQuery): Promise<void> {
    const handler = this.preCheckoutHandlers.get(botToken);
    if (handler) {
      await handler(botToken, query);
      log.debug({ queryId: query.id }, 'Pre-checkout query handled');
    } else {
      log.warn({ queryId: query.id }, 'No pre-checkout handler registered for this bot');
    }
  }

  private async handleSuccessfulPayment(botToken: string, payment: SuccessfulPayment, message: TelegramMessage): Promise<void> {
    const handler = this.successfulPaymentHandlers.get(botToken);
    if (handler) {
      await handler(botToken, payment, message);
      log.debug({ chargeId: payment.telegram_payment_charge_id }, 'Successful payment handled');
    } else {
      log.warn({ chargeId: payment.telegram_payment_charge_id }, 'No payment handler registered for this bot');
    }
  }
}
