import { setEventListener, watchIMEvent } from './helper/event';
import { getMessageList } from './helper/get-message-list';
import { init } from './helper/init';

import { login } from './helper/login';
import { sendMessage } from './helper/send-message';
import { getTIM } from './helper/tim';
import { waitReady } from './helper/wait-ready';


import type { TimType, TimInstanceType, EventCallback, UpdateMyProfileOptions } from './types';


export class IM {
  tim?: TimInstanceType;

  // eslint-disable-next-line @typescript-eslint/naming-convention
  TIM?: TimType;

  constructor({
    appId,
    logLevel = 0,
  }: {
    appId: number;
    logLevel?: number;
  }) {
    this.tryGetTIM().then(() => {
      this.tim = this.init(appId, logLevel);
    });
  }

  get isReady() {
    return this.tim?.isReady || false;
  }

  set isReady(value) {
    this.tim?.updateReadyStatus?.(!!value);
  }

  get isOnline() {
    return this.tim?.isOnline || false;
  }

  set isOnline(value) {
    this.tim?.updateOnlineStatus?.(!!value);
  }


  async setEventListener(type?: string, cb?: EventCallback) {
    if (!type) {
      console.warn('[setEventListener] error! Empty type!');
      return;
    }
    if (!cb) {
      console.warn('[setEventListener] error! Empty callback!');
      return;
    }

    await this.tryGetTIM();
    setEventListener({ type, cb, TIM: this.TIM! });
  }

  async setReceivedMessagesListener(cb: EventCallback) {
    await this.tryGetTIM();
    this.setEventListener(this.TIM?.EVENT.MESSAGE_RECEIVED || '', cb);
  }

  async setKickedOutListener(cb: EventCallback) {
    await this.tryGetTIM();
    this.setEventListener(this.TIM?.EVENT.KICKED_OUT, cb);
  }

  async setReadyListener(cb: EventCallback) {
    await this.tryGetTIM();
    this.setEventListener(this.TIM?.EVENT.SDK_READY, cb);
  }

  async setConversationUpdateListener(cb: EventCallback) {
    await this.tryGetTIM();
    this.setEventListener(this.TIM?.EVENT.CONVERSATION_LIST_UPDATED, cb);
  }

  async setUnreadMsgCountUpdatedListener(cb: EventCallback) {
    await this.tryGetTIM();
    this.setEventListener(this.TIM?.EVENT.TOTAL_UNREAD_MESSAGE_COUNT_UPDATED, cb);
  }

  async innerLogin({
    userId,
    userSig,
  }: {
    userId: string;
    userSig: string;
  }) {
    await this.tryGetTIM();
    this.tim?.updateUserId?.(userId);
    this.tim?.updateUserSig?.(userSig);

    return login({
      userId,
      userSig,
      tim: this.tim!,
    });
  }

  async innerLogout() {
    await this.tryGetTIM();
    return this.tim?.logout();
  }

  async sendMessage({ to, text = '' }: {
    to: string;
    text: string;
  }) {
    await this.tryGetTIM();

    const { tim } = this;
    const { isOnline, userId, userSig } = tim || {};

    if (!isOnline && userId && userSig) {
      await login({ userId, userSig, tim: tim! });
    }

    await waitReady(tim!, this.TIM!);

    return await sendMessage({
      tim: tim!,
      to,
      text,
      TIM: this.TIM!,
    });
  }

  async getMessageList({
    id,
    // count = 15,
    nextMsgId,
  }: {
    id: string;
    nextMsgId: string;
  }) {
    await this.tryGetTIM();

    return getMessageList({
      conversationId: id,
      // count,
      nextMsgId,
      tim: this.tim!,
      TIM: this.TIM!,
    });
  }

  async deleteConversation(id: string) {
    await this.tryGetTIM();

    return this.tim?.deleteConversation(id);
  }

  // 将所有会话的未读消息全部设置为已读
  async sendAllMegRead() {
    await this.tryGetTIM();

    return this.tim?.setAllMessageRead({
      scope: this.TIM!.TYPES.READ_ALL_MSG!,
    });
  }

  // 将某会话下所有未读消息已读上报
  async setMessageRead(id: string) {
    await this.tryGetTIM();

    return this.tim?.setMessageRead({ conversationID: id });
  }

  // 修改个人标配资料
  async updateMyProfile(profile: UpdateMyProfileOptions) {
    await this.tryGetTIM();
    await waitReady(this.tim!, this.TIM!);
    return this.tim?.updateMyProfile(profile);
  }

  // 获取全量的会话列表
  async getConversationList() {
    await this.tryGetTIM();
    return this.tim?.getConversationList();
  }


  async tryGetTIM() {
    try {
      const res = await getTIM();
      this.TIM = res;
    } catch (err) {
      console.warn('[tryGetTIM] error: ', err);
    }
  }

  private init(appId: number, logLevel: number) {
    const tim = init({
      appId,
      TIM: this.TIM!,
      logLevel,
    });

    watchIMEvent({
      tim,
      TIM: this.TIM!,
    });
    return tim;
  }

  // private async waitReady() {
  //   return waitReady(this.tim, this.TIM);
  // }
}

