/*
 * https://github.com/morethanwords/tweb
 * Copyright (C) 2019-2021 Eduard Kuzmenko
 * https://github.com/morethanwords/tweb/blob/master/LICENSE
 */

import {SliderSuperTab} from '../../slider';
import AppSelectPeers from '../../appSelectPeers';
import appDialogsManager from '../../../lib/appManagers/appDialogsManager';
import {MyDialogFilter as DialogFilter} from '../../../lib/storages/filters';
import ButtonIcon from '../../buttonIcon';
import CheckboxField from '../../checkboxField';
import Button from '../../button';
import AppEditFolderTab from './editFolder';
import I18n, {i18n, LangPackKey, _i18n, join} from '../../../lib/langPack';
import {toast} from '../../toast';
import copy from '../../../helpers/object/copy';
import forEachReverse from '../../../helpers/array/forEachReverse';
import setInnerHTML from '../../../helpers/dom/setInnerHTML';
import wrapEmojiText from '../../../lib/richTextProcessor/wrapEmojiText';
import {REAL_FOLDERS} from '../../../lib/mtproto/mtproto_config';
import rootScope from '../../../lib/rootScope';
import {MTAppConfig} from '../../../lib/mtproto/appConfig';
import {attachClickEvent, simulateClickEvent} from '../../../helpers/dom/clickEvent';
import SettingSection from '../../settingSection';

export default class AppIncludedChatsTab extends SliderSuperTab {
  private editFolderTab: AppEditFolderTab;
  private confirmBtn: HTMLElement;

  private selector: AppSelectPeers;
  private type: 'included' | 'excluded';
  private filter: DialogFilter;
  private originalFilter: DialogFilter;

  private dialogsByFilters: Map<DialogFilter, Set<PeerId>>;
  private limit: number;

  public init(
    filter: DialogFilter,
    type: 'included' | 'excluded',
    editFolderTab: AppIncludedChatsTab['editFolderTab']
  ) {
    this.originalFilter = filter;
    this.filter = copy(this.originalFilter);
    this.type = type;
    this.editFolderTab = editFolderTab;

    this.content.remove();
    this.container.classList.add('included-chatlist-container');
    this.confirmBtn = ButtonIcon('check btn-confirm blue', {noRipple: true});
    this.confirmBtn.style.display = 'none';

    this.header.append(this.confirmBtn);

    attachClickEvent(this.confirmBtn, async() => {
      const selected = this.selector.getSelected();

      // this.filter.pFlags = {};

      if(this.type === 'included') {
        for(const key in this.filter.pFlags) {
          if(key.indexOf('exclude_') === 0) {
            continue;
          }

          // @ts-ignore
          delete this.filter.pFlags[key];
        }
      } else {
        for(const key in this.filter.pFlags) {
          if(key.indexOf('exclude_') !== 0) {
            continue;
          }

          // @ts-ignore
          delete this.filter.pFlags[key];
        }
      }

      const peerIds: PeerId[] = [];
      for(const key of selected) {
        if(key.isPeerId()) {
          peerIds.push(key.toPeerId());
        } else {
          // @ts-ignore
          this.filter.pFlags[key] = true;
        }
      }

      let cmp: (peerId: PeerId) => boolean;
      if(this.type === 'included') {
        cmp = (peerId) => peerIds.includes(peerId);
      } else {
        cmp = (peerId) => !peerIds.includes(peerId);
      }

      forEachReverse(this.filter.pinnedPeerIds, (peerId, idx) => {
        if(!cmp(peerId)) {
          this.filter.pinnedPeerIds.splice(idx, 1);
          this.filter.pinned_peers.splice(idx, 1);
        }
      });

      const other = this.type === 'included' ? 'excludePeerIds' : 'includePeerIds';
      const otherLegacy = this.type === 'included' ? 'exclude_peers' : 'include_peers';
      forEachReverse(this.filter[other], (peerId, idx) => {
        if(peerIds.includes(peerId)) {
          this.filter[other].splice(idx, 1);
          this.filter[otherLegacy].splice(idx, 1);
        }
      });

      this.filter[this.type === 'included' ? 'includePeerIds' : 'excludePeerIds'] = peerIds;
      this.filter[this.type === 'included' ? 'include_peers' : 'exclude_peers'] = await Promise.all(peerIds.map((peerId) => this.managers.appPeersManager.getInputPeerById(peerId)));
      // this.filter.pinned_peers = this.filter.pinned_peers.filter((peerId) => this.filter.include_peers.includes(peerId));

      this.editFolderTab.setFilter(this.filter, false);
      this.close();
    }, {listenerSetter: this.listenerSetter});

    const onAppConfig = (appConfig: MTAppConfig) => {
      this.limit = rootScope.premium ? appConfig.dialog_filters_chats_limit_premium : appConfig.dialog_filters_chats_limit_default;
    };

    this.listenerSetter.add(rootScope)('app_config', onAppConfig);

    this.dialogsByFilters = new Map();
    return Promise.all([
      this.managers.filtersStorage.getDialogFilters().then(async(filters) => {
        await Promise.all(filters.filter((filter) => !REAL_FOLDERS.has(filter.id)).map(async(filter) => {
          const dialogs = await this.managers.dialogsStorage.getFolderDialogs(filter.id);
          const peerIds = dialogs.map((d) => d.peerId);
          this.dialogsByFilters.set(filter, new Set(peerIds));
        }));
      }),

      this.managers.apiManager.getAppConfig().then((appConfig) => {
        onAppConfig(appConfig);
      })
    ]);
  }

  checkbox(selected?: boolean) {
    const checkboxField = new CheckboxField({
      round: true
    });
    if(selected) {
      checkboxField.input.checked = selected;
    }

    return checkboxField.label;
  }

  renderResults = async(peerIds: PeerId[]) => {
    // const other = this.type === 'included' ? this.filter.exclude_peers : this.filter.include_peers;

    await this.managers.appUsersManager.getContacts();
    peerIds.forEach((peerId) => {
      // if(other.includes(peerId)) return;

      const {dom} = appDialogsManager.addDialogNew({
        peerId: peerId,
        container: this.selector.scrollable,
        rippleEnabled: true,
        avatarSize: 'abitbigger'
      });

      const selected = this.selector.selected.has(peerId);
      dom.containerEl.append(this.checkbox(selected));
      // if(selected) dom.listEl.classList.add('active');

      const foundInFilters: HTMLElement[] = [];
      this.dialogsByFilters.forEach((dialogs, filter) => {
        if(dialogs.has(peerId)) {
          const span = document.createElement('span');
          setInnerHTML(span, wrapEmojiText(filter.title));
          foundInFilters.push(span);
        }
      });

      const joined = join(foundInFilters, false);
      joined.forEach((el) => {
        dom.lastMessageSpan.append(el);
      });
    });
  };

  onOpen() {
    this.confirmBtn.style.display = this.type === 'excluded' ? '' : 'none';
    this.setTitle(this.type === 'included' ? 'FilterAlwaysShow' : 'FilterNeverShow');

    const filter = this.filter;

    const categoriesSection = new SettingSection({
      noDelimiter: true,
      name: 'FilterChatTypes'
    });

    categoriesSection.container.classList.add('folder-categories');

    let details: {[flag: string]: {ico: string, text: LangPackKey}};
    if(this.type === 'excluded') {
      details = {
        exclude_muted: {ico: 'mute', text: 'ChatList.Filter.MutedChats'},
        exclude_archived: {ico: 'archive', text: 'ChatList.Filter.Archive'},
        exclude_read: {ico: 'readchats', text: 'ChatList.Filter.ReadChats'}
      };
    } else {
      details = {
        contacts: {ico: 'newprivate', text: 'ChatList.Filter.Contacts'},
        non_contacts: {ico: 'noncontacts', text: 'ChatList.Filter.NonContacts'},
        groups: {ico: 'group', text: 'ChatList.Filter.Groups'},
        broadcasts: {ico: 'newchannel', text: 'ChatList.Filter.Channels'},
        bots: {ico: 'bots', text: 'ChatList.Filter.Bots'}
      };
    }

    const f = document.createDocumentFragment();
    for(const key in details) {
      const button = Button('btn-primary btn-transparent folder-category-button', {icon: details[key].ico, text: details[key].text});
      button.dataset.peerId = key;
      button.append(this.checkbox());
      f.append(button);
    }
    categoriesSection.content.append(f);

    // ///////////////

    const selectedPeers = (this.type === 'included' ? filter.includePeerIds : filter.excludePeerIds).slice();

    this.selector = new AppSelectPeers({
      appendTo: this.container,
      onChange: this.onSelectChange,
      peerType: ['dialogs'],
      renderResultsFunc: this.renderResults,
      placeholder: 'Search',
      sectionNameLangPackKey: 'FilterChats',
      managers: this.managers
    });
    this.selector.selected = new Set(selectedPeers);

    let addedInitial = false;
    const _add = this.selector.add.bind(this.selector);
    this.selector.add = (peerId, title, scroll) => {
      if(this.selector.selected.size >= this.limit && addedInitial && !details[peerId]) {
        const el: HTMLInputElement = this.selector.list.querySelector(`[data-peer-id="${peerId}"] [type="checkbox"]`);
        if(el) {
          setTimeout(() => {
            el.checked = false;
          }, 0);
        }

        const str = I18n.format(this.type === 'excluded' ? 'ChatList.Filter.Exclude.LimitReached': 'ChatList.Filter.Include.LimitReached', true);
        toast(str);
        return;
      }

      const div = _add(peerId, details[peerId] ? i18n(details[peerId].text) : undefined, scroll);
      if(details[peerId]) {
        div.querySelector('avatar-element').classList.add('tgico-' + details[peerId].ico);
      }
      return div;
    };

    this.selector.scrollable.container.append(categoriesSection.container, this.selector.scrollable.container.lastElementChild);

    this.selector.addInitial(selectedPeers);
    addedInitial = true;

    for(const flag in filter.pFlags) {
      // @ts-ignore
      if(details.hasOwnProperty(flag) && !!filter.pFlags[flag]) {
        simulateClickEvent(categoriesSection.content.querySelector(`[data-peer-id="${flag}"]`) as HTMLElement);
      }
    }
  }

  onSelectChange = (length: number) => {
    // const changed = !deepEqual(this.filter, this.originalFilter);
    if(this.type === 'included') {
      this.confirmBtn.style.display = length ? '' : 'none';
    }
  };

  onCloseAfterTimeout() {
    if(this.selector) {
      this.selector.container.remove();
      this.selector = null;
    }

    return super.onCloseAfterTimeout();
  }
}
