import {
  makeAutoObservable,
  runInAction,
} from 'mobx';

import { rpc } from '../api/request';
import {
  ArgsChannelSendMessageInput,
  ShmChannelMessageType,
  ShmChannelType,
} from '../api/types';
import { IS_DEV } from '../config';
import newMessageSound from '../new.mp3';
import store from './store';

const MESSAGES_CHECK_INTERVAL_MS = 5000;
const newMessageAudio = new Audio(newMessageSound);

export class ChannelStore {
  channelID: string | undefined = undefined;
  channel: ShmChannelType | null = null;
  joinInChannel: boolean | null = null;

  messagesList: ShmChannelMessageType[] = [];
  messagesLoading = false;
  /** >0 пока идёт любой полный channelMessages (loadMessages или догрузка в поллинге); поллинг тикает только при 0. */
  messagesFetchInFlight = 0;
  messagesLastHash: string | null = null;
  loadMessagesPollingInterval: ReturnType<typeof setInterval> | null = null;

  replyMsg: ShmChannelMessageType | null = null;
  sending = false;
  messageText = '';
  recording = false;
  /** После отправки сообщения — скролл вниз после прихода `loadMessages`. */
  pendingScrollToBottom = false;

  constructor() {
    makeAutoObservable(this);
  }

  get pinnedMessage(): ShmChannelMessageType | null {
    const pinned = this.messagesList?.filter((e) => e.pinned?.enabled);
    return pinned?.[pinned.length - 1] ?? null;
  }

  openChannel(channelID: string | undefined) {
    this.channelID = channelID;
    this.channel = null;
    this.joinInChannel = null;
    this.messagesList = [];
    this.messagesLoading = false;
    this.messagesFetchInFlight = 0;
    this.replyMsg = null;
    this.pendingScrollToBottom = false;

    if (this.loadMessagesPollingInterval) {
      clearInterval(this.loadMessagesPollingInterval);
      this.loadMessagesPollingInterval = null;
    }

    if (channelID) {
      this.refreshChannel();
    }
  }

  refreshChannel() {
    this.channel = null;
    this.joinInChannel = null;
    if (!this.channelID) return;

    rpc.channelInfo({ channel: this.channelID }).then(({ result: data }) => {
      runInAction(() => {
        if (data) {
          this.channel = data;
          const isMember = data?.members?.find(
            (member) => member.owner == store.userID
          );
          this.joinInChannel = !!isMember;
        }
      });
    });
  }

  updateChannelInfo() {
    if (!this.channelID) return;

    rpc.channelInfo({ channel: this.channelID }).then(({ result: data }) => {
      runInAction(() => {
        if (data) {
          this.channel = data;
          const isMember = data?.members?.find(
            (member) => member.owner == store.userID
          );
          this.joinInChannel = !!isMember;
        }
      });
    });
  }



  loadMessages() {
    if (!this.channel?._id) return;

    const isInitialLoad = this.messagesList.length === 0;
    if (isInitialLoad) {
      this.messagesLoading = true;
    }

    runInAction(() => {
      this.messagesFetchInFlight++;
    });

    rpc
      .channelMessages(
        { channel: this.channel._id, limit: 50, offset: 0 },
        ['shmChannelMessages']
      )
      .then(({ result: json }) => {
        runInAction(() => {
          this.messagesList = json?.data ?? [];
          this.messagesLastHash = json?.hash ?? null;
          this.messagesLoading = false;
        });
      })
      .catch(() => {
        runInAction(() => {
          this.messagesLoading = false;
          this.pendingScrollToBottom = false;
        });
      })
      .finally(() => {
        runInAction(() => {
          this.messagesFetchInFlight--;
        });
      });
  }

  startMessagesPolling(scrollToBottom?: () => void) {
    if (!this.channel?._id) return;

    this.stopMessagesPolling();
    this.loadMessagesPollingInterval = setInterval(() => {
      if (this.messagesFetchInFlight > 0) {
        return;
      }

      rpc
        .channelMessages({ channel: this.channel!._id!, limit: 50, offset: 0, onlyHash: true })
        .then(({ result: newValue }) => {

          if (IS_DEV) {
            console.log('POLLING Проверка на новые сообщения')
            console.log('POLLING Пришло новое значение', newValue);
            console.log('POLLING Текущее значение', this.messagesLastHash);

          }

          if (newValue?.hash != null && newValue.hash !== this.messagesLastHash) {

            console.log('POLLING Не равны, обновляем информацию о канале')


            this.updateChannelInfo();
            runInAction(() => {
              this.messagesFetchInFlight++;
            });
            rpc
              .channelMessages(
                { channel: this.channel!._id!, limit: 50, offset: 0 },
                ['shmChannelMessages']
              )
              .then(({ result: json }) => {
                runInAction(() => {
                  const prevLastId = this.messagesList[this.messagesList.length - 1]?._id;
                  const newList = json?.data ?? [];
                  const newLastMessage = newList[newList.length - 1];
                  const newLastId = newLastMessage?._id;
                  if (prevLastId && newLastId && prevLastId !== newLastId) {
                    scrollToBottom?.();
                    if (newLastMessage?.owner != store.userID) {
                      newMessageAudio.play();
                    }
                  }
                  this.messagesList = newList;
                  this.messagesLastHash = json?.hash ?? null;
                  if (IS_DEV) {

                    console.log('POLLING Обновлены сообщения', json?.hash);

                  }
                });
              })
              .finally(() => {
                runInAction(() => {
                  this.messagesFetchInFlight--;
                });
              });
          }
        });
    }, MESSAGES_CHECK_INTERVAL_MS);
  }

  stopMessagesPolling() {
    if (this.loadMessagesPollingInterval) {
      clearInterval(this.loadMessagesPollingInterval);
      this.loadMessagesPollingInterval = null;
    }
  }

  setJoinInChannel(value: boolean) {
    this.joinInChannel = value;
  }

  setReplyMsg(msg: ShmChannelMessageType | null) {
    this.replyMsg = msg;
  }

  setMessageText(text: string) {
    this.messageText = text;
  }

  setRecording(value: boolean) {
    this.recording = value;
  }

  setSending(value: boolean) {
    this.sending = value;
  }

  clearPendingScrollToBottom() {
    this.pendingScrollToBottom = false;
  }

  async sendMessage(params: ArgsChannelSendMessageInput) {
    if (!this.channel?._id) return;

    params.channel = this.channel._id;
    if (this.replyMsg?._id) {
      params.reply = this.replyMsg._id;
    }

    this.sending = true;
    try {
      await rpc.channelSendMessage(params);
      runInAction(() => {
        if (this.replyMsg) this.replyMsg = null;
        if (params.text) this.messageText = '';
        this.pendingScrollToBottom = true;
      });
      this.loadMessages();
    } finally {
      runInAction(() => {
        this.sending = false;
      });
    }
  }

  resetCompose() {
    this.replyMsg = null;
    this.messageText = '';
  }
}

export const channelStore = new ChannelStore();
