import { IContact } from './Contact.interface';
import AvatarSet from './ui/AvatarSet';
import Client from './Client';
import Account from './Account';
import Storage from './Storage';
import { Strophe } from './vendor/Strophe';

enum TYPE {
   PLACEHOLDER,
   IMAGE,
}

const KEY_SOURCE_ACCOUNT = 'clientAvatar';
const KEY_TYPE = 'clientAvatarType';
const KEY_SESSION_FLAG = 'clientAvatar';

export default class ClientAvatar {
   private static instance: ClientAvatar;

   public static get(): ClientAvatar {
      if (!ClientAvatar.instance) {
         ClientAvatar.instance = new ClientAvatar(Client.getStorage());
      }

      return ClientAvatar.instance;
   }

   private elements = [];
   private contact: IContact;

   private constructor(private storage: Storage) {
      let accounts = Client.getAccountManager().getAccounts();

      if (accounts.length === 0) {
         this.reset();
      }

      storage.registerHook('accounts', newValue => {
         if ((newValue || []).length === 0) {
            this.reset();
         }
      });

      storage.registerHook(KEY_SOURCE_ACCOUNT, (sourceAccountUid, oldValue) => {
         if (sourceAccountUid) {
            let account = Client.getAccountManager().getAccount(sourceAccountUid);

            if (account.getSessionStorage().getItem(KEY_SESSION_FLAG)) {
               this.setSourceContact(account.getContact());
            } else {
               this.reset();
            }
         } else if (oldValue) {
            this.reset();
         }
      });
   }

   private reset() {
      this.storage.removeItem(KEY_SOURCE_ACCOUNT);
      this.storage.removeItem(KEY_TYPE);

      AvatarSet.clear(this.elements);
   }

   public registerAccount(account: Account) {
      if (this.getSourceAccountUid() === account.getUid()) {
         if (account.getSessionStorage().getItem(KEY_SESSION_FLAG)) {
            this.setSourceContact(account.getContact());
         } else {
            this.reset();
         }
      }

      account.registerConnectionHook((status, condition) => {
         if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
            account
               .getContact()
               .getAvatar()
               .then(avatar => {
                  if (!this.getSourceAccountUid() || this.getCurrentType() === TYPE.PLACEHOLDER) {
                     this.setSourceAccount(account, TYPE.IMAGE);
                  }
               })
               .catch(() => {
                  if (!this.getSourceAccountUid()) {
                     this.setSourceAccount(account);
                  }
               });
         }
         //@TODO [MA] update avatar if account goes offline
      });
   }

   private setSourceAccount(account, type = TYPE.PLACEHOLDER) {
      account.getSessionStorage().setItem(KEY_SESSION_FLAG, true);

      this.storage.setItem(KEY_SOURCE_ACCOUNT, account.getUid());
      this.storage.getItem(KEY_TYPE, type + '');
   }

   private getSourceAccountUid(): string {
      return this.storage.getItem(KEY_SOURCE_ACCOUNT);
   }

   private getCurrentType(): TYPE {
      return parseInt(this.storage.getItem(KEY_TYPE), 10);
   }

   private setSourceContact(contact: IContact) {
      if (this.contact !== contact) {
         for (let element of this.elements) {
            AvatarSet.get(contact).addElement(element);
         }
      }

      this.contact = contact;
   }

   public addElement(element) {
      this.elements.push(element);

      if (this.contact) {
         AvatarSet.get(this.contact).addElement(element);
      }
   }

   public reload() {
      if (this.contact) {
         AvatarSet.get(this.contact).reload();
      }
   }
}
