import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import TelegramBot from 'node-telegram-bot-api';
import { Change } from 'src/models/change.model';
import { TelegramBotService } from 'src/telegram-bot/telegram-bot.service';

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace StatusChangeAdapter {
  export type MsgFromBatch = {
    initiatorId: number;
    recipientId: number;
    issueId: number;
    createdAt: number;
    msg: string;
    options?: TelegramBot.SendMessageOptions;
  };
}

@Injectable()
export class StatusChangeAdapterService {
  private logger = new Logger(StatusChangeAdapterService.name);
  private periodValidityNotification: number;

  constructor(
    private telegramBotService: TelegramBotService,
    private configService: ConfigService,
  ) {
    this.periodValidityNotification = this.configService.get<number>(
      'periodValidityNotification',
    );
  }

  // TODO: Удалить устаревший метод send

  /**
   * @deprecated
   * @see StatusChangeAdapterService.batchSend
   */
  async send(change: Change): Promise<boolean[]> {
    const promises = change.messages.map((m) => {
      if (!m || !m.recipient || !m.recipient.id || !m.notification_message) {
        return true;
      }
      return this.telegramBotService.sendMessageByRedmineId(
        m.recipient.id,
        m.notification_message,
        { parse_mode: 'HTML' },
      );
    });
    return await Promise.all(promises);
  }

  async batchSend(changes: Change[]): Promise<void> {
    const messages = this.getMessages(changes).map((item) => {
      item.options = { parse_mode: 'HTML' };
      return item;
    });
    this.logger.debug(`Change messages for sending to telegram - ${JSON.stringify(messages)}`);
    for (let i = 0; i < messages.length; i++) {
      const message = messages[i];
      await this.telegramBotService.sendMessageByRedmineId(
        message.recipientId,
        message.msg,
        message.options,
      );
    }
  }

  private getMessages(changes: Change[]): StatusChangeAdapter.MsgFromBatch[] {
    const res: StatusChangeAdapter.MsgFromBatch[] = [];
    const store: Record<string, StatusChangeAdapter.MsgFromBatch> = {};
    const nowTimestamp = new Date().getTime();
    for (let i = 0; i < changes.length; i++) {
      const change = changes[i];
      if (
        nowTimestamp - change.created_on_timestamp >
        this.periodValidityNotification
      ) {
        this.logger.debug(
          `Skipping sending due to the prescription ` +
            `of the origin of the event - ` +
            `issue_id = ${change.issue_id}, ` +
            `messages = ${change.messages.map((m) => m.notification_message).filter((m) => !!m)}`
        );
        continue;
      }
      for (let j = 0; j < change.messages.length; j++) {
        const message = change.messages[j];
        if (!message.notification_message) continue;
        if (change.initiator.id == message.recipient.id) continue;
        const item: StatusChangeAdapter.MsgFromBatch = {
          initiatorId: change.initiator.id,
          recipientId: message.recipient.id,
          createdAt: change.created_on_timestamp,
          issueId: change.issue_id,
          msg: message.notification_message,
        };
        const key = this.keyForMsgFromBatch(item);
        if (
          !store[key] ||
          (store[key] && store[key].createdAt < item.createdAt)
        ) {
          store[key] = item;
        }
      }
    }
    for (const key in store) {
      if (Object.prototype.hasOwnProperty.call(store, key)) {
        const item = store[key];
        res.push(item);
      }
    }
    return res;
  }

  private keyForMsgFromBatch(item: StatusChangeAdapter.MsgFromBatch): string {
    return `${item.issueId}-${item.recipientId}`;
  }
}
