import { useCallback, useEffect, useMemo } from '../../../../lib/teact/teact';

import { ApiFormattedText, ApiMessage } from '../../../../api/types';
import { GlobalActions } from '../../../../global/types';

import { DRAFT_DEBOUNCE, EDITABLE_INPUT_ID } from '../../../../config';
import usePrevious from '../../../../hooks/usePrevious';
import { debounce } from '../../../../util/schedulers';
import focusEditableElement from '../../../../util/focusEditableElement';
import parseMessageInput from '../helpers/parseMessageInput';
import getMessageTextAsHtml from '../helpers/getMessageTextAsHtml';
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
import useBeforeUnload from '../../../../hooks/useBeforeUnload';

// Used to avoid running debounced callbacks when chat changes.
let currentChatId: number | undefined;
let currentThreadId: number | undefined;

export default (
  draft: ApiFormattedText | undefined,
  chatId: number,
  threadId: number,
  html: string,
  htmlRef: { current: string },
  setHtml: (html: string) => void,
  editedMessage: ApiMessage | undefined,
  saveDraft: GlobalActions['saveDraft'],
  clearDraft: GlobalActions['clearDraft'],
) => {
  const updateDraft = useCallback((draftChatId: number, draftThreadId: number) => {
    if (htmlRef.current.length && !editedMessage) {
      saveDraft({ chatId: draftChatId, threadId: draftThreadId, draft: parseMessageInput(htmlRef.current!) });
    } else {
      clearDraft({ chatId: draftChatId, threadId: draftThreadId });
    }
  }, [clearDraft, editedMessage, htmlRef, saveDraft]);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const runDebouncedForSaveDraft = useMemo(() => debounce((cb) => cb(), DRAFT_DEBOUNCE, false), [chatId]);

  const prevChatId = usePrevious(chatId);
  const prevThreadId = usePrevious(threadId);

  // Save draft on chat change
  useEffect(() => {
    currentChatId = chatId;
    currentThreadId = threadId;

    return () => {
      currentChatId = undefined;
      currentThreadId = undefined;

      updateDraft(chatId, threadId);
    };
  }, [chatId, threadId, updateDraft]);

  // Restore draft on chat change
  useEffect(() => {
    if (chatId === prevChatId && threadId === prevThreadId) {
      return;
    }

    if (!draft) {
      return;
    }

    setHtml(getMessageTextAsHtml(draft));

    requestAnimationFrame(() => {
      const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;
      focusEditableElement(messageInput, true);
    });
  }, [chatId, threadId, draft, setHtml, updateDraft, prevChatId, prevThreadId]);

  // Update draft when input changes
  const prevHtml = usePrevious(html);
  useEffect(() => {
    if (!chatId || !threadId || prevChatId !== chatId || prevThreadId !== threadId || prevHtml === html) {
      return;
    }

    if (html.length) {
      runDebouncedForSaveDraft(() => {
        if (currentChatId !== chatId || currentThreadId !== threadId) {
          return;
        }

        updateDraft(chatId, threadId);
      });
    } else {
      updateDraft(chatId, threadId);
    }
  }, [chatId, html, prevChatId, prevHtml, prevThreadId, runDebouncedForSaveDraft, threadId, updateDraft]);

  const handleBlur = useCallback(() => {
    if (chatId && threadId) {
      updateDraft(chatId, threadId);
    }
  }, [chatId, threadId, updateDraft]);

  useBackgroundMode(handleBlur);
  useBeforeUnload(handleBlur);
};
