import { ResolutionUnitSpecifier } from "fast-png";
import AvatarElement from "../../components/avatar";
import DialogsContextMenu from "../../components/dialogsContextMenu";
import { horizontalMenu } from "../../components/horizontalMenu";
import { attachContextMenuListener, putPreloader } from "../../components/misc";
import { ripple } from "../../components/ripple";
//import Scrollable from "../../components/scrollable";
import Scrollable, { ScrollableX } from "../../components/scrollable";
import appSidebarLeft from "../../components/sidebarLeft";
import { formatDateAccordingToToday } from "../../helpers/date";
import { isTouchSupported } from "../../helpers/touchSupport";
import { isSafari } from "../../helpers/userAgent";
import { logger, LogLevels } from "../logger";
import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope";
import { cancelEvent, escapeRegExp, findUpClassName, positionElementByIndex } from "../utils";
import appChatsManager from "./appChatsManager";
import appImManager, { AppImManager } from "./appImManager";
import appMessagesManager, { Dialog, MyDialogFilter as DialogFilter } from "./appMessagesManager";
import appPeersManager from './appPeersManager';
import appStateManager from "./appStateManager";
import appUsersManager, { User } from "./appUsersManager";

type DialogDom = {
  avatarEl: AvatarElement,
  captionDiv: HTMLDivElement,
  titleSpan: HTMLSpanElement,
  statusSpan: HTMLSpanElement,
  lastTimeSpan: HTMLSpanElement,
  unreadMessagesSpan: HTMLSpanElement,
  lastMessageSpan: HTMLSpanElement,
  containerEl: HTMLDivElement,
  listEl: HTMLLIElement,
  muteAnimationTimeout?: number
};

const testScroll = false;
//const USEPINNEDDELIMITER = false;

export class AppDialogsManager {
  public _chatList = document.getElementById('dialogs') as HTMLUListElement;
  public chatList = this._chatList;
  
  //public pinnedDelimiter: HTMLDivElement;
  
  public doms: {[peerID: number]: DialogDom} = {};
  public lastActiveListElement: HTMLElement = null;

  /* private rippleCallback: (value?: boolean | PromiseLike<boolean>) => void = null;
  private lastClickID = 0;
  private lastGoodClickID = 0; */

  public chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
  private chatsPreloader: HTMLDivElement;

  public loadDialogsPromise: Promise<any>;
  public loadedAll = false;

  public scroll: Scrollable = null;
  public _scroll: Scrollable = null;
  
  private log = logger('DIALOGS', LogLevels.log | LogLevels.error | LogLevels.warn | LogLevels.debug);

  public contextMenu = new DialogsContextMenu();

  public chatLists: {[filterID: number]: HTMLUListElement} = {
    0: this.chatList,
    1: appSidebarLeft.archivedTab.chatList
  };
  public filterID = 0;
  private folders: {[k in 'menu' | 'container' | 'menuScrollContainer']: HTMLElement} = {
    menu: document.getElementById('folders-tabs'),
    menuScrollContainer: null,
    container: document.getElementById('folders-container')
  };
  private filtersRendered: {
    [filterID: string]: {
      menu: HTMLElement, 
      container: HTMLElement,
      unread: HTMLElement,
      title: HTMLElement
    }
  } = {};
  private showFiltersTimeout: number;
  private allUnreadCount: HTMLElement;

  private accumulateArchivedTimeout: number;

  constructor() {
    this.chatsPreloader = putPreloader(null, true);

    this.allUnreadCount = this.folders.menu.querySelector('.unread-count');
    
    /* if(USEPINNEDDELIMITER) {
      this.pinnedDelimiter = document.createElement('div');
      this.pinnedDelimiter.classList.add('pinned-delimiter');
      this.pinnedDelimiter.appendChild(document.createElement('span'));
    } */

    this.folders.menuScrollContainer = this.folders.menu.parentElement;

    this.scroll = this._scroll = new Scrollable(this.chatsContainer, 'CL', this.chatList, 500);
    this.scroll.onScrolledBottom = this.onChatsScroll;
    this.scroll.setVirtualContainer(this.chatList);
    //this.scroll.attachSentinels();

    if(isTouchSupported && isSafari) {
      let allowUp: boolean, allowDown: boolean, slideBeginY: number;
      const container = this.scroll.container;
      container.addEventListener('touchstart', (event) => {
        allowUp = container.scrollTop > 0;
        allowDown = (container.scrollTop < container.scrollHeight - container.clientHeight);
        // @ts-ignore
        slideBeginY = event.pageY;
      });
      
      container.addEventListener('touchmove', (event: any) => {
        var up = (event.pageY > slideBeginY);
        var down = (event.pageY < slideBeginY);
        slideBeginY = event.pageY;
        if((up && allowUp) || (down && allowDown)) {
          event.stopPropagation();
        } else if(up || down) {
          event.preventDefault();
        }
      });
    }

    this.setListClickListener(this.chatList, null, true);

    /* if(testScroll) {
      let i = 0;
      let add = () => {
        let li = document.createElement('li');
        li.dataset.id = '' + i;
        li.id = '' + i;
        li.innerHTML = `<div class="rp"><avatar-element style="background-color: rgb(166, 149, 231); font-size: 0px;"><img src="assets/img/pepe.jpg"></avatar-element><div class="user-caption"><p><span class="user-title">${i}</span><span><span class="message-status"></span><span class="message-time">18:33</span></span></p><p><span class="user-last-message"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;
        i++;
        this.scroll.append(li);
      };
      for(let i = 0; i < 100; ++i) {
        add();
      }
      (window as any).addElement = add;
    } */

    $rootScope.$on('user_update', (e) => {
      const userID = e.detail;
      const user = appUsersManager.getUser(userID);
      const dialog = appMessagesManager.getDialogByPeerID(user.id)[0];
      //console.log('updating user:', user, dialog);

      if(dialog && !appUsersManager.isBot(dialog.peerID) && dialog.peerID != $rootScope.myID) {
        const online = user.status?._ == 'userStatusOnline';
        const dom = this.getDialogDom(dialog.peerID);

        if(dom) {
          dom.avatarEl.classList.toggle('is-online', online);
        }
      }

      if($rootScope.selectedPeerID == user.id) {
        appImManager.setPeerStatus();
      }
    });

    $rootScope.$on('dialog_top', (e) => {
      let dialog: any = e.detail;

      this.setLastMessage(dialog);
      this.setDialogPosition(dialog);

      //this.setPinnedDelimiter();
      this.setFiltersUnreadCount();
    });

    $rootScope.$on('dialog_flush', (e) => {
      let peerID: number = e.detail.peerID;
      let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
      if(dialog) {
        this.setLastMessage(dialog);
        this.validateForFilter();
        this.setFiltersUnreadCount();
      }
    });

    $rootScope.$on('dialogs_multiupdate', (e) => {
      const dialogs = e.detail;

      for(const id in dialogs) {
        const dialog = dialogs[id];
        this.updateDialog(dialog);
      }

      //this.setPinnedDelimiter();
      this.validateForFilter();
      this.setFiltersUnreadCount();
    });

    $rootScope.$on('dialog_drop', (e) => {
      let {peerID, dialog} = e.detail;

      let dom = this.getDialogDom(peerID);
      if(dom) {
        dom.listEl.remove();
        delete this.doms[peerID];
        this.scroll.reorder();
      }

      this.setFiltersUnreadCount();
    });

    $rootScope.$on('dialog_unread', (e) => {
      let info = e.detail;

      let dialog = appMessagesManager.getDialogByPeerID(info.peerID)[0];
      if(dialog) {
        this.setUnreadMessages(dialog);

        if(dialog.peerID == $rootScope.selectedPeerID) {
          appImManager.updateUnreadByDialog(dialog);
        }

        this.validateForFilter();
        this.setFiltersUnreadCount();
      }
    });

    $rootScope.$on('dialog_notify_settings', e => {
      const dialog = appMessagesManager.getDialogByPeerID(e.detail)[0];
      if(dialog) {
        this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted
      }
    });

    $rootScope.$on('peer_changed', (e) => {
      let peerID = e.detail;

      let lastPeerID = this.lastActiveListElement && +this.lastActiveListElement.getAttribute('data-peerID');
      if(this.lastActiveListElement && lastPeerID != peerID) {
        this.lastActiveListElement.classList.remove('active');
        this.lastActiveListElement = null;
      }
    
      if(lastPeerID != peerID) {
        let dom = this.getDialogDom(peerID);
        if(dom) {
          this.lastActiveListElement = dom.listEl;
          dom.listEl.classList.add('active');
        }
      }
    });

    $rootScope.$on('filter_update', (e) => {
      const filter: DialogFilter = e.detail;
      if(!this.filtersRendered[filter.id]) {
        this.addFilter(filter);
        return;
      } else if(filter.id == this.filterID) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate
        //this.validateForFilter();
        const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);
        this.validateForFilter();
        for(let i = 0, length = folder.length; i < length; ++i) {
          const dialog = folder[i];
          this.updateDialog(dialog);
        }
        this.setFiltersUnreadCount();
      }

      const elements = this.filtersRendered[filter.id];
      elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
    });

    $rootScope.$on('filter_delete', (e) => {
      const filter: DialogFilter = e.detail;
      const elements = this.filtersRendered[filter.id];
      if(!elements) return;

      // set tab
      //(this.folders.menu.firstElementChild.children[Math.max(0, filter.id - 2)] as HTMLElement).click();
      (this.folders.menu.firstElementChild.children[0] as HTMLElement).click();

      elements.container.remove();
      elements.menu.remove();
      
      delete this.chatLists[filter.id];
      delete this.filtersRendered[filter.id];

      if(!Object.keys(this.filtersRendered).length) {
        this.folders.menuScrollContainer.classList.add('hide');
      }
    });

    /* $rootScope.$on('filter_pinned_order', (e) => {
      const {order, id} = e.detail as {order: number[], id: number};
      if(this.prevTabID != id) {
        return;
      }

      for(const peerID of order) {
        this.updateDialog(appMessagesManager.getDialogByPeerID(peerID)[0]);
      }
    }); */

    const foldersScrollable = new ScrollableX(this.folders.menuScrollContainer);
    this.chatsContainer.prepend(this.folders.menuScrollContainer);
    const selectTab = horizontalMenu(this.folders.menu, this.folders.container, (id, tabContent) => {
      /* if(id != 0) {
        id += 1;
      } */

      foldersScrollable.scrollIntoView(this.folders.menu.firstElementChild.children[id] as HTMLElement, true, 250);

      id = +tabContent.dataset.filterID || 0;

      if(this.filterID == id) return;

      this.chatLists[id].innerHTML = '';
      this.scroll.setVirtualContainer(this.chatLists[id]);
      this.filterID = id;
      this.onTabChange();
    }, () => {
      for(const folderID in this.chatLists) {
        if(+folderID != this.filterID) {
          this.chatLists[folderID].innerHTML = '';
        }
      }
    });

    //selectTab(0);
    (this.folders.menu.firstElementChild.firstElementChild as HTMLElement).click();

    /* false &&  */appStateManager.getState().then(() => {
      return appMessagesManager.filtersStorage.getDialogFilters();
    }).then(filters => {
      for(const filterID in filters) {
        this.addFilter(filters[filterID]);
      }

      return this.loadDialogs();
    }).then(result => {
      //this.setPinnedDelimiter();
      //appSidebarLeft.onChatsScroll();
      //this.loadDialogs(1);
      appMessagesManager.getConversationsAll('', 1).then(() => {
        this.accumulateArchivedUnread();
      });
    });
  }

  private updateDialog(dialog: Dialog) {
    if(!dialog) {
      return;
    }

    if(!this.doms.hasOwnProperty(dialog.peerID)) {
      this.addDialog(dialog);
    }

    if(this.getDialogDom(dialog.peerID)) {
      this.setLastMessage(dialog);
      this.setDialogPosition(dialog);
    }
  }

  onTabChange = () => {
    this.doms = {};
    this.loadedAll = false;
    this.lastActiveListElement = null;
    this.loadDialogsPromise = undefined;
    this.chatList = this.chatLists[this.filterID];
    this.loadDialogs();
  };

  public setFilterUnreadCount(filterID: number, folder?: Dialog[]) {
    const unreadSpan = filterID == 0 ? this.allUnreadCount : this.filtersRendered[filterID]?.unread;
    if(!unreadSpan) {
      return;
    }

    folder = folder || appMessagesManager.dialogsStorage.getFolder(filterID);
    const sum = folder.reduce((acc, dialog) => acc + +!!dialog.unread_count, 0);
    
    unreadSpan.innerText = sum ? '' + sum : '';
  }

  public setFiltersUnreadCount() {
    for(const filterID in this.filtersRendered) {
      this.setFilterUnreadCount(+filterID);
    }

    this.setFilterUnreadCount(0);
  }

  /**
   * Удалит неподходящие чаты из списка, но не добавит их(!)
   */
  public validateForFilter() {
    // !WARNING, возможно это было зачем-то, но комментарий исправил архивирование
    //if(this.filterID == 0) return;

    const folder = appMessagesManager.dialogsStorage.getFolder(this.filterID);
    let affected = false;
    for(const _peerID in this.doms) {
      const peerID = +_peerID;

      // если больше не подходит по фильтру, удаляем
      if(folder.findIndex((dialog) => dialog.peerID == peerID) === -1) {
        const listEl = this.doms[peerID].listEl;
        listEl.remove();
        affected = true;

        if(this.lastActiveListElement == listEl) {
          this.lastActiveListElement = null;
        }
      }
    }

    if(affected) {
      this.scroll.reorder();
    }
  }

  public addFilter(filter: DialogFilter) {
    if(this.filtersRendered[filter.id]) return;

    const li = document.createElement('li');
    const span = document.createElement('span');
    const titleSpan = document.createElement('span');
    titleSpan.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
    const unreadSpan = document.createElement('span');
    unreadSpan.classList.add('unread-count');
    const i = document.createElement('i');
    span.append(titleSpan, unreadSpan, i);
    li.append(span);
    ripple(li);

    const containerToAppend = this.folders.menu.firstElementChild as HTMLUListElement;
    positionElementByIndex(li, containerToAppend, filter.orderIndex + 1); // because 0 is All
    //containerToAppend.append(li);

    const ul = document.createElement('ul');
    const div = document.createElement('div');
    div.append(ul);
    div.dataset.filterID = '' + filter.id;
    //this.folders.container.append(div);
    positionElementByIndex(div, this.folders.container, filter.orderIndex + 1); // because 0 is All

    this.chatLists[filter.id] = ul;
    this.setListClickListener(ul, null, true);

    if(!this.showFiltersTimeout) {
      this.showFiltersTimeout = window.setTimeout(() => {
        this.showFiltersTimeout = 0;
        this.folders.menuScrollContainer.classList.remove('hide');
        this.setFiltersUnreadCount();
      }, 0);
    }

    this.filtersRendered[filter.id] = {
      menu: li,
      container: div,
      unread: unreadSpan,
      title: titleSpan
    };
  }

  public async loadDialogs() {
    if(testScroll) {
      return;
    }
    
    if(this.loadDialogsPromise/*  || 1 == 1 */) return this.loadDialogsPromise;
    
    if(!this.chatList.childElementCount) {
      const container = this.chatList.parentElement;
      container.append(this.chatsPreloader);
    }

    //return;

    const filterID = this.filterID;

    const storage = appMessagesManager.dialogsStorage.getFolder(filterID);
    let offsetIndex = 0;
    
    for(let i = storage.length - 1; i >= 0; --i) {
      const dialog = storage[i];
      if(this.getDialogDom(dialog.peerID)) {
        offsetIndex = dialog.index;
        break;
      }
    }
    //let offset = storage[storage.length - 1]?.index || 0;

    try {
      //console.time('getDialogs time');

      const loadCount = 50/*this.chatsLoadCount */;

      const getConversationPromise = (this.filterID > 1 ? appUsersManager.getContacts() as Promise<any> : Promise.resolve()).then(() => {
        return appMessagesManager.getConversations('', offsetIndex, loadCount, filterID);
      });

      this.loadDialogsPromise = getConversationPromise;
      
      const result = await getConversationPromise;

      if(this.filterID != filterID) {
        return;
      }

      //console.timeEnd('getDialogs time');
      
      if(result && result.dialogs && result.dialogs.length) {
        result.dialogs.forEach((dialog) => {
          this.addDialog(dialog);
        });
      }

      if(!result.dialogs.length || this.chatList.childElementCount == result.count) { // loaded all
        this.loadedAll = true;
      }

      this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount);
      this.scroll.onScroll();
    } catch(err) {
      this.log.error(err);
    }
    
    this.chatsPreloader.remove();
    this.loadDialogsPromise = undefined;
  }
  
  onChatsScroll = () => {
    if(this.loadedAll || this.loadDialogsPromise) return;
    this.log('onChatsScroll');
    this.loadDialogs();
  }

  public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false) {
    list.addEventListener('click', (e: Event) => {
      cancelEvent(e);

      this.log('dialogs click list');
      let target = e.target as HTMLElement;
      let elem = target.classList.contains('rp') ? target : findUpClassName(target, 'rp');

      if(!elem) {
        return;
      }

      elem = elem.parentElement;

      let samePeer = this.lastActiveListElement == elem;

      if(this.lastActiveListElement && !samePeer) {
        this.lastActiveListElement.classList.remove('active');
      }

      let result: ReturnType<AppImManager['setPeer']>;
      //console.log('appDialogsManager: lock lazyLoadQueue');
      if(elem) {
        if(onFound) onFound();

        let peerID = +elem.getAttribute('data-peerID');
        let lastMsgID = +elem.dataset.mid || undefined;

        if(!samePeer) {
          elem.classList.add('active');
          this.lastActiveListElement = elem;
        }

        result = appImManager.setPeer(peerID, lastMsgID);

        /* if(result instanceof Promise) {
          this.lastGoodClickID = this.lastClickID;
          appImManager.lazyLoadQueue.lock();
        } */
      } else {
        result = appImManager.setPeer(0);
      }
    }, {capture: true});

    if(withContext) {
      attachContextMenuListener(list, this.contextMenu.onContextMenu);
    }
  }

  public setDialogPosition(dialog: Dialog, pos?: number) {
    const dom = this.getDialogDom(dialog.peerID);
    if(!dom) {
      return;
    }

    if(pos === undefined) {
      pos = appMessagesManager.dialogsStorage.getDialog(dialog.peerID, this.filterID)[1];
    }

    if(positionElementByIndex(dom.listEl, this.chatList, pos)) {
      this.scroll.reorder();

      this.log.debug('setDialogPosition:', dialog, dom, pos);
    }
  }

  /* public setPinnedDelimiter() {
    if(!USEPINNEDDELIMITER) return;

    let index = -1;
    let dialogs = appMessagesManager.dialogsStorage.getFolder(0);
    for(let dialog of dialogs) {
      if(dialog.pFlags?.pinned) {
        index++;
      }
    }

    let currentIndex = (this.pinnedDelimiter.parentElement && whichChild(this.pinnedDelimiter.parentElement)) ?? -1;

    if(index == currentIndex) return;

    let children = this.chatList.children;

    let modifying: HTMLElement[] = [];
    if(currentIndex != -1 && children.length > currentIndex) {
      let li = children[currentIndex] as HTMLElement;
      modifying.push(li);
    }

    if(index != -1 && children.length > index) {
      let li = children[index] as HTMLElement;
      modifying.push(li);
      li.append(this.pinnedDelimiter);
    } else {
      this.pinnedDelimiter.remove();
    }
      
    modifying.forEach(elem => {
      this.scroll.updateElement(elem);
    });
  } */

  public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {
    if(!lastMessage) {
      lastMessage = appMessagesManager.getMessage(dialog.top_message);
    }

    ///////console.log('setlastMessage:', lastMessage);
    if(!dom) {
      dom = this.getDialogDom(dialog.peerID);

      if(!dom) {
        //this.log.error('no dom for dialog:', dialog, lastMessage, dom, highlightWord);
        return;
      }
    }

    if(lastMessage._ == 'messageEmpty' || (lastMessage._ == 'messageService' && !lastMessage.rReply)) {
      dom.lastMessageSpan.innerHTML = '';
      dom.lastTimeSpan.innerHTML = '';
      delete dom.listEl.dataset.mid;
      return;
    }

    let peer = dialog.peer;
    let peerID = dialog.peerID;
    //let peerID = appMessagesManager.getMessagePeer(lastMessage);

    //console.log('setting last message:', lastMessage);

    /* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {

      if(highlightWord && lastMessage.message) {
        let lastMessageText = appMessagesManager.getRichReplyText(lastMessage, '');

        let messageText = lastMessage.message;
        let entities = RichTextProcessor.parseEntities(messageText.replace(/\n/g, ' '), {noLinebreakers: true});
          let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');
          let match: any;

          if(!entities) entities = [];
          let found = false;
          while((match = regExp.exec(messageText)) !== null) {
            entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index});
            found = true;
          }
    
          if(found) {
            entities.sort((a: any, b: any) => a.offset - b.offset);
          }
    
        let messageWrapped = RichTextProcessor.wrapRichText(messageText, {
          noLinebreaks: true, 
          entities: entities, 
          noTextFormat: true
        });

        dom.lastMessageSpan.innerHTML = lastMessageText + messageWrapped;
      } else if(!lastMessage.deleted) {
        dom.lastMessageSpan.innerHTML = lastMessage.rReply;
      } else {
        dom.lastMessageSpan.innerHTML = '';
      }
  
      /* if(lastMessage.from_id == auth.id) { // You:  */
      if(peer._ != 'peerUser' && peerID != lastMessage.fromID) {
        const sender = appPeersManager.getPeer(lastMessage.fromID);
        if(sender && sender.id) {
          const senderBold = document.createElement('b');

          let str = '';
          if(sender.id == $rootScope.myID) {
            str = 'You';
          } else {
            //str = sender.first_name || sender.last_name || sender.username;
            str = appPeersManager.getPeerTitle(lastMessage.fromID, true, true);
          }

          //senderBold.innerText = str + ': ';
          senderBold.innerHTML = RichTextProcessor.wrapRichText(str, {noLinebreaks: true}) + ': ';
          //console.log(sender, senderBold.innerText);
          dom.lastMessageSpan.prepend(senderBold);
        } //////// else console.log('no sender', lastMessage, peerID);
      }
    }

    if(!lastMessage.deleted) {
      dom.lastTimeSpan.innerHTML = formatDateAccordingToToday(new Date(lastMessage.date * 1000));
    } else dom.lastTimeSpan.innerHTML = '';

    if(this.doms[peerID] == dom) {
      this.setUnreadMessages(dialog);
    } else { // means search
      dom.listEl.dataset.mid = lastMessage.mid;
    }
  }

  public setUnreadMessages(dialog: Dialog) {
    const dom = this.getDialogDom(dialog.peerID);

    if(dialog.folder_id == 1) {
      this.accumulateArchivedUnread();
    }

    if(!dom) {
      //this.log.error('setUnreadMessages no dom!', dialog);
      return;
    }

    const isMuted = (dialog.notify_settings?.mute_until * 1000) > Date.now();
    const wasMuted = dom.listEl.classList.contains('is-muted');
    if(!isMuted && wasMuted) {
      dom.listEl.classList.add('backwards');

      if(dom.muteAnimationTimeout) clearTimeout(dom.muteAnimationTimeout);
      dom.muteAnimationTimeout = window.setTimeout(() => {
        delete dom.muteAnimationTimeout;
        dom.listEl.classList.remove('backwards', 'is-muted');
      }, 200);
    } else {
      dom.listEl.classList.toggle('is-muted', isMuted);
    }

    const lastMessage = appMessagesManager.getMessage(dialog.top_message);
    if(lastMessage._ != 'messageEmpty' && !lastMessage.deleted && 
      lastMessage.fromID == $rootScope.myID && lastMessage.peerID != $rootScope.myID/*  && 
      dialog.read_outbox_max_id */) { // maybe comment, 06.20.2020
      const outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)
        /*  && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020
    
      //console.log('outgoing', outgoing, lastMessage);
  
      if(outgoing) {
        dom.statusSpan.classList.remove('tgico-checks');
        dom.statusSpan.classList.add('tgico-check');
      } else {
        dom.statusSpan.classList.remove('tgico-check');
        dom.statusSpan.classList.add('tgico-checks');
      }
    } else dom.statusSpan.classList.remove('tgico-check', 'tgico-checks');

    dom.unreadMessagesSpan.innerText = '';
    dom.unreadMessagesSpan.classList.remove('tgico-pinnedchat');

    const filter = appMessagesManager.filtersStorage.filters[this.filterID];
    let isPinned: boolean;
    if(filter) {
      isPinned = filter.pinned_peers.findIndex(peerID => peerID == dialog.peerID) !== -1;
    } else {
      isPinned = !!dialog.pFlags.pinned;
    }

    if(dialog.unread_count || dialog.pFlags.unread_mark) {
      //dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count ? formatNumber(dialog.unread_count, 1) : ' ');
      dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count || ' ');
      dom.unreadMessagesSpan.classList.add('unread');
    } else if(isPinned) {
      dom.unreadMessagesSpan.classList.remove('unread');
      dom.unreadMessagesSpan.classList.add('tgico-pinnedchat');
    }
  }

  public accumulateArchivedUnread() {
    if(this.accumulateArchivedTimeout) return;
    this.accumulateArchivedTimeout = window.setTimeout(() => {
      this.accumulateArchivedTimeout = 0;
      const dialogs = appMessagesManager.dialogsStorage.getFolder(1);
      const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);
      $rootScope.$broadcast('dialogs_archived_unread', {count: sum});
    }, 0);
  }

  public getDialogDom(peerID: number) {
    return this.doms[peerID];
  }

  public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true) {
    let dialog: Dialog;
    
    if(typeof(_dialog) === 'number') {
      let originalDialog = appMessagesManager.getDialogByPeerID(_dialog)[0];
      if(!originalDialog) {
        originalDialog = {
          peerID: _dialog,
          pFlags: {}
        } as any;
      }

      dialog = originalDialog;
    } else {
      dialog = _dialog;
    }

    let peerID: number = dialog.peerID;

    if(!container) {
      if(this.doms[peerID]) return;

      const filter = appMessagesManager.filtersStorage.filters[this.filterID];
      if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || (!filter && this.filterID != dialog.folder_id)) {
        return;
      }
    }

    let title = appPeersManager.getPeerTitle(peerID, false, onlyFirstName);

    let avatarEl = new AvatarElement();
    avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');
    avatarEl.setAttribute('peer', '' + peerID);
    avatarEl.classList.add('dialog-avatar');

    if(drawStatus && peerID != $rootScope.myID && dialog.peer) {
      let peer = dialog.peer;
      
      switch(peer._) {
        case 'peerUser':
          let user = appUsersManager.getUser(peerID);
          //console.log('found user', user);
  
          if(user.status && user.status._ == 'userStatusOnline') {
            avatarEl.classList.add('is-online');
          }
  
          break;
        default:
          break;
      }
    }

    let captionDiv = document.createElement('div');
    captionDiv.classList.add('user-caption');

    let titleSpan = document.createElement('span');
    titleSpan.classList.add('user-title');

    if(peerID == $rootScope.myID && meAsSaved) {
      title = onlyFirstName ? 'Saved' : 'Saved Messages';
    } 

    titleSpan.innerHTML = title;
    //p.classList.add('')

    // в других случаях иконка верификации не нужна (а первый - это главные чатлисты)
    if(!container) {
      let peer: any;

      // for muted icon
      titleSpan.classList.add('tgico');

      if(peerID < 0) {
        peer = appChatsManager.getChat(-peerID);
      } else {
        peer = appUsersManager.getUser(peerID);
      }

      if(peer?.pFlags?.verified) {
        titleSpan.classList.add('is-verified');
        const i = document.createElement('i');
        i.classList.add('verified-icon');
        titleSpan.append(i);
      }
    }
    
    let span = document.createElement('span');
    span.classList.add('user-last-message');

    //captionDiv.append(titleSpan);
    //captionDiv.append(span);

    let paddingDiv = document.createElement('div');
    paddingDiv.classList.add('rp');
    paddingDiv.append(avatarEl, captionDiv);

    if(rippleEnabled) {
      ripple(paddingDiv);
      /* ripple(paddingDiv, (id) => {
        this.log('dialogs click element');
        this.lastClickID = id;
  
        return new Promise((resolve, reject) => {
          this.rippleCallback = resolve;
          //setTimeout(() => resolve(), 100);
          //window.requestAnimationFrame(() => window.requestAnimationFrame(() => resolve()));
        });
      }, (id) => {
        //console.log('appDialogsManager: ripple onEnd called!');
        if(id == this.lastGoodClickID) {
          appImManager.lazyLoadQueue.unlock();
        }
      }); */
    }
    

    let li = document.createElement('li');
    li.append(paddingDiv);
    li.setAttribute('data-peerID', '' + peerID);

    let statusSpan = document.createElement('span');
    statusSpan.classList.add('message-status');

    let lastTimeSpan = document.createElement('span');
    lastTimeSpan.classList.add('message-time');

    let unreadMessagesSpan = document.createElement('span');

    let titleP = document.createElement('p');

    let rightSpan = document.createElement('span');
    rightSpan.append(statusSpan, lastTimeSpan);
    titleP.append(titleSpan, rightSpan);

    let messageP = document.createElement('p');
    messageP.append(span, unreadMessagesSpan);

    captionDiv.append(titleP, messageP);

    let dom: DialogDom = {
      avatarEl,
      captionDiv,
      titleSpan,
      statusSpan,
      lastTimeSpan,
      unreadMessagesSpan,
      lastMessageSpan: span,
      containerEl: paddingDiv,
      listEl: li
    };

    /* let good = false;
    for(const folderID in this.chatLists) {
      if(this.chatLists[folderID] == container) {
        good = true;
      }
    } */
    if(!container/*  || good */) {
      this.scroll.append(li);

      this.doms[dialog.peerID] = dom;

      if($rootScope.selectedPeerID == peerID) {
        li.classList.add('active');
        this.lastActiveListElement = li;
      }

      /* if(container) {
        container.append(li);
      } */

      this.setLastMessage(dialog);
    } else {
      container.append(li);
    }
    
    return {dom, dialog};
  }

  public setTyping(dialog: Dialog, user: User) {
    const dom = this.getDialogDom(dialog.peerID);
    if(!dom) {
      return;
    }

    let str = '';
    if(dialog.peerID < 0) {
      let s = user.rFirstName || user.username;
      if(!s) return;
      str = s + ' ';
    } 

    const senderBold = document.createElement('i');
    str += 'typing...';
    senderBold.innerHTML = str;

    dom.lastMessageSpan.innerHTML = '';
    dom.lastMessageSpan.append(senderBold);
    dom.lastMessageSpan.classList.add('user-typing');
  }

  public unsetTyping(dialog: Dialog) {
    const dom = this.getDialogDom(dialog.peerID);
    if(!dom) {
      return;
    }

    dom.lastMessageSpan.classList.remove('user-typing');
    this.setLastMessage(dialog, null, dom);
  }
}

const appDialogsManager = new AppDialogsManager();
export default appDialogsManager;
