import appDialogsManager from "../lib/appManagers/appDialogsManager";
import Scrollable from "./scrollable";
import appMessagesIDsManager from "../lib/appManagers/appMessagesIDsManager";
import appUsersManager from "../lib/appManagers/appUsersManager";
import appPeersManager from '../lib/appManagers/appPeersManager';
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import { escapeRegExp } from "../lib/utils";
import { formatPhoneNumber } from "./misc";
import appChatsManager from "../lib/appManagers/appChatsManager";
import SearchInput from "./searchInput";
import { Peer } from "../layer";
import $rootScope from "../lib/rootScope";

export class SearchGroup {
  container: HTMLDivElement;
  nameEl: HTMLDivElement;
  list: HTMLUListElement;

  constructor(public name: string, public type: string, private clearable = true, className?: string, clickable = true) {
    this.list = document.createElement('ul');
    this.container = document.createElement('div');
    if(className) this.container.className = className;
    
    if(name) {
      this.nameEl = document.createElement('div');
      this.nameEl.classList.add('search-group__name');
      this.nameEl.innerText = name;
      this.container.append(this.nameEl);
    }
    
    this.container.classList.add('search-group', 'search-group-' + type);
    this.container.append(this.list);
    this.container.style.display = 'none';

    if(clickable) {
      appDialogsManager.setListClickListener(this.list);
    }
  }

  clear() {
    this.container.style.display = 'none';

    if(this.clearable) {
      this.list.innerHTML = '';
    }
  }

  setActive() {
    this.container.style.display = '';
  }
}

/**
 * * Saved будет использована только для вывода одного элемента - избранное
 */
type SearchGroupType = 'saved' | 'contacts' | 'globalContacts' | 'messages' | string;

export default class AppSearch {
  private minMsgID = 0;
  private loadedCount = -1;
  private foundCount = -1;
  private offsetRate = 0;
  private loadedContacts = false;

  private searchPromise: Promise<void> = null;
  private searchTimeout: number = 0;

  private query = '';

  public listsContainer: HTMLDivElement = null;

  private peerID = 0; // 0 - means global

  private scrollable: Scrollable;

  constructor(public container: HTMLElement, public searchInput: SearchInput, public searchGroups: {[group in SearchGroupType]: SearchGroup}, public onSearch?: (count: number) => void) {
    this.scrollable = new Scrollable(this.container);
    this.listsContainer = this.scrollable.container as HTMLDivElement;
    for(let i in this.searchGroups) {
      this.listsContainer.append(this.searchGroups[i as SearchGroupType].container);
    }

    if(this.searchGroups.messages) {
      this.scrollable.setVirtualContainer(this.searchGroups.messages.list);
    }

    this.searchInput.onChange = (value) => {
      /* if(!value.trim()) {
        //this.peerID = 0;
        return;
      } */
      
      this.query = value;
      this.reset(false);
      this.searchMore();
    };

    this.scrollable.onScrolledBottom = () => {
      if(!this.query.trim()) return;
    
      if(!this.searchTimeout) {
        this.searchTimeout = window.setTimeout(() => {
          this.searchMore();
          this.searchTimeout = 0;
        }, 0);
      }
    };
  }

  public reset(all = true) {
    if(all) {
      this.searchInput.value = '';
      this.query = '';
      this.peerID = 0;
    }

    this.minMsgID = 0;
    this.loadedCount = -1;
    this.foundCount = -1;
    this.offsetRate = 0;
    this.loadedContacts = false;

    for(let i in this.searchGroups) {
      this.searchGroups[i as SearchGroupType].clear();
    }
    
    this.searchPromise = null;
  }

  public beginSearch(peerID?: number) {
    if(peerID) {
      this.peerID = peerID;
    }
    
    this.searchInput.input.focus();
  }

  private renderSaved() {
    const group = this.searchGroups.contacts;
    let {dialog, dom} = appDialogsManager.addDialog($rootScope.myID, group.list, false);
    dom.lastMessageSpan.innerHTML = 'chat with yourself';
    group.setActive();
  }
  
  public searchMore() {
    if(this.searchPromise) return this.searchPromise;
    
    const query = this.query;
    
    if(!query.trim()) {
      this.onSearch && this.onSearch(0);
      return;
    }
    
    if(this.foundCount != -1 && this.loadedCount >= this.foundCount) {
      return Promise.resolve();
    }
    
    const maxID = appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0] || 0;

    if(!this.peerID && !maxID && !this.loadedContacts) {
      let renderedSaved = false;
      if('saved messages'.includes(query.toLowerCase()) 
        || appUsersManager.getUser($rootScope.myID).sortName.includes(query.toLowerCase())/*  && this.searchGroups.hasOwnProperty('saved') */) {
        this.renderSaved();
        renderedSaved = true;
      }

      appUsersManager.searchContacts(query, 20).then((contacts) => {
        if(this.searchInput.value != query) {
          return;
        }

        this.loadedContacts = true;

        // set saved message as first peer to render
        const peer = contacts.my_results.findAndSplice(p => (p as Peer.peerUser).user_id == $rootScope.myID);
        if(peer) {
          contacts.my_results.unshift(peer);
        }

        //console.log('input search contacts result:', contacts);

        let setResults = (results: Peer[], group: SearchGroup, showMembersCount = false) => {
          results.forEach((inputPeer) => {
            let peerID = appPeersManager.getPeerID(inputPeer);

            if(peerID == $rootScope.myID) {
              if(!renderedSaved) {
                this.renderSaved();
              }

              return;
            }

            let peer = appPeersManager.getPeer(peerID);
            let originalDialog = appMessagesManager.getDialogByPeerID(peerID)[0];

            //////////this.log('contacts peer', peer);
          
            if(!originalDialog) {
              /////////this.log('no original dialog by peerID:', peerID);
              
              originalDialog = {
                peerID: peerID,
                pFlags: {},
                peer: peer
              } as any;
            }
            
            let {dialog, dom} = appDialogsManager.addDialog(originalDialog, group.list, false);

            if(showMembersCount && (peer.participants_count || peer.participants)) {
              let regExp = new RegExp(`(${escapeRegExp(query)})`, 'gi');
              dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
              dom.lastMessageSpan.innerText = appChatsManager.getChatMembersString(-peerID);
            } else {
              let username = appPeersManager.getPeerUsername(peerID);
              if(!username) {
                let user = appUsersManager.getUser(peerID);
                if(user && user.phone) {
                  username = '+' + formatPhoneNumber(user.phone).formatted;
                }
              } else {
                username = '@' + username;
              }

              dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';
            }
          });

          if(results.length) group.setActive();
          else if(renderedSaved) { // удалить все пункты снизу
            Array.from(group.list.children).slice(1).forEach(c => c.remove());
          } else {
            group.clear();
          }
        };

        setResults(contacts.my_results, this.searchGroups.contacts, true);
        setResults(contacts.results, this.searchGroups.globalContacts);
      });
    }
    
    return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => {
      this.searchPromise = null;
      
      if(this.searchInput.value != query) {
        return;
      }
      
      //console.log('input search result:', this.peerID, query, null, maxID, 20, res);
      
      const {count, history, next_rate} = res;
      
      if(history[0] == this.minMsgID) {
        history.shift();
      }
      
      const searchGroup = this.searchGroups.messages;
      searchGroup.setActive();

      history.forEach((msgID: number) => {
        const message = appMessagesManager.getMessage(msgID);
        let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
        
        if(!originalDialog) {
          ////////this.log('no original dialog by message:', message);
          
          originalDialog = {
            peerID: message.peerID,
            pFlags: {},
            peer: message.peer_id
          } as any;
        }
        
        const {dialog, dom} = appDialogsManager.addDialog(originalDialog, this.scrollable/* searchGroup.list */, false);
        appDialogsManager.setLastMessage(dialog, message, dom, query);
      });
      
      this.minMsgID = history[history.length - 1];
      this.offsetRate = next_rate;
      
      if(this.loadedCount == -1) {
        this.loadedCount = 0;
      }
      this.loadedCount += history.length;
      
      if(this.foundCount == -1) {
        this.foundCount = count;
        this.onSearch && this.onSearch(this.foundCount);
      }
    }).catch(err => {
      console.error('search error', err);
      this.searchPromise = null;
    });
  }
}
