import { DragAndDropState } from './DragAndDropState';
import { FiltersMap } from '@wix/bex-core';
import { createPortal } from 'react-dom';
import React, { useEffect, useState } from 'react';
import { observer } from 'mobx-react-lite';
import { visuallyHidden } from '../VisuallyHidden';
import { usePageContext, useWixPatternsContainer } from '@wix/bex-core/react';
import { reaction, runInAction } from 'mobx';

export interface DragAndDropAnnouncementsProps<T, F extends FiltersMap> {
  state: DragAndDropState<T, F>;
  dataHook?: string;
}

function _DragAndDropAnnouncements<T, F extends FiltersMap>(
  props: DragAndDropAnnouncementsProps<T, F>,
) {
  const { state, dataHook } = props;

  const { modalsContainerRef } = usePageContext();

  const {
    environment: { language },
    translate: t,
  } = useWixPatternsContainer();

  const {
    collection: { total },
  } = state;

  const [localState, setLocalState] = useState(() =>
    runInAction(() => {
      const current = {
        status: state.status,
        active: state.active,
        over: state.over,
      } as const;
      return {
        current,
        prev: null as typeof current | null | undefined,
      };
    }),
  );

  useEffect(
    () =>
      reaction(
        () => ({
          status: state.status,
          active: state.active,
          over: state.over,
        }),
        (current, prev) => {
          setLocalState({
            current,
            prev,
          });
        },
        { fireImmediately: true },
      ),
    [],
  );

  const { over, status, active } = localState.current;

  const announcement = (() => {
    switch (status) {
      case 'start':
        if (active) {
          return t('cairo.dragAndDrop.live-region.itemGrabbed.sr');
        }

        return;

      case 'over':
        if (over && localState.prev?.status !== 'start') {
          return t('cairo.dragAndDrop.live-region.itemDragged.sr', {
            currentNumber: over.index + 1,
            totalNumber: total,
          });
        }

        if (active) {
          return t('cairo.dragAndDrop.live-region.itemGrabbed.sr');
        }

        return;
      case 'end':
        if (over) {
          if (over.id === active?.id) {
            return t('cairo.dragAndDrop.reorder-cancelled.sr');
          }

          const activeOrPrev = active || localState.prev?.active;
          if (activeOrPrev) {
            return t('cairo.dragAndDrop.live-region.itemDropped.sr', {
              currentNumber: activeOrPrev.index + 1,
            });
          }

          return;
        }
        return;
      case 'cancel':
        return t('cairo.dragAndDrop.reorder-cancelled.sr');
    }

    return;
  })();

  let child = (
    <div
      data-hook={dataHook}
      style={visuallyHidden}
      role="status"
      aria-live="assertive"
      aria-atomic
      lang={language}
    >
      {announcement}
    </div>
  );

  if (!modalsContainerRef.current) {
    return null;
  }

  child = createPortal(child, modalsContainerRef.current);

  return child;
}

export const DragAndDropAnnouncements = observer(_DragAndDropAnnouncements);
