import { RedmineTypes } from '@app/event-emitter/models/redmine-types';
import { SaveResponse } from '@app/event-emitter/models/save-response';
import { UsersService } from '@app/event-emitter/users/users.service';
import { Injectable, Logger } from '@nestjs/common';
import { Subject } from 'rxjs';
import { IssueAndPersonalParsedMessageModel } from 'src/models/issue-and-personal-parsed-message.model';
import { PersonalParsedMessage } from 'src/models/personal-parsed-message.model';

@Injectable()
export class PersonalNotificationsService {
  private userNameRe = /@([\wА-Яа-яЁё]+) ([\wА-Яа-яЁё]+)@/g;
  private userName2Re = /@([\wА-Яа-яЁё\.]+)/g;
  private logger = new Logger(PersonalNotificationsService.name);

  $messages = new Subject<IssueAndPersonalParsedMessageModel>();

  constructor(private usersService: UsersService) {}

  async analize(
    data: SaveResponse,
  ): Promise<IssueAndPersonalParsedMessageModel[]> {
    this.logger.debug(
      `Analize personal messages for issue ` +
        `#${data.current.id} (${data.current.subject}) start`,
    );
    const pMessages = data.journalsDiff.map(async (journal) => {
      const message = await this.getMessage(journal);
      if (message) {
        this.logger.log(
          `Found personal message in issue #${data.current.id} ` +
            `(${data.current.subject}) - ` +
            `message = ${JSON.stringify(message.message)} ` +
            `from sender ${message.sender} ` +
            `for recipients ${JSON.stringify(message.recipients)}`,
        );
        this.$messages.next({
          issue: data.current,
          personalParsedMessage: message,
        });
      }
      return message;
    });
    const res = (await Promise.all(pMessages))
      .filter((m) => Boolean(m))
      .map((m) => ({ issue: data.current, personalParsedMessage: m }));
    this.logger.debug(
      `Analize personal messages for issue ` +
        `#${data.current.id} (${data.current.subject}) finished`,
    );
    return res;
  }

  private async getMessage(
    journal: RedmineTypes.Journal,
  ): Promise<PersonalParsedMessage | null> {
    if (!journal.notes) {
      return null;
    }
    const notes = journal.notes;
    const results = notes.matchAll(this.userNameRe);
    const recipients: number[] = [];
    let result = results.next();
    while (!result.done) {
      if (result.value && result.value[1] && result.value[2]) {
        const firstname = result.value[1];
        const lastname = result.value[2];
        const user = await this.usersService.findUserByName(
          firstname,
          lastname,
        );
        if (user) recipients.push(user.id);
      }
      result = results.next();
    }
    const results2 = notes.matchAll(this.userName2Re);
    let result2 = results2.next();
    while (!result2.done) {
      if (result.value && result.value[1]) {
        const login = result.value[1];
        const user = await this.usersService.findUserByLogin(login);
        if (user) recipients.push(user.id);
      }
      result2 = results2.next();
    }
    if (recipients.length > 0) {
      return {
        message: notes,
        sender: journal.user.id,
        recipients: recipients,
      };
    }
    return null;
  }
}
