import Router from 'next/router';
import { ofType } from 'redux-observable';
import { concat, of } from 'rxjs';
import { filter, mergeMap } from 'rxjs/operators';

import { TYPE_ERROR } from '@/modules/@common/notify/constants';
import {
  DND_MAIN_LIST_OF_VIDEO_TYPE,
  DND_PLAYLIST_TYPE,
  DND_PLAYLIST_VIDEO_TYPE,
} from '@/modules/editorial/constants/dnd';
import { QUERY_PARAM_TAB, TAB_WATCH } from '@/modules/editorial/constants/routing';

import { getChannelFromStore } from '../../helpers/channels';
import * as watchesSelectors from '../selectors';
import { setWatchesAction, updateChannelAction, updatePlaylistAction } from '../slices';
import { dragAndDropEndSelector, videosSelector } from '@/modules/editorial/editorialSearchResults/redux/selectors';
import { dragAndDropEndAction } from '@/modules/editorial/editorialSearchResults/redux/slices';
import { parseDndId } from '@/modules/editorial/helpers/createDndId';
import { reorderVideos } from '@/modules/editorial/RightSideBar/common/helpers';
import { showNotificationAction } from '@/modules/layout/redux/slices';

export default (action$, state$) =>
  action$.pipe(
    ofType(dragAndDropEndAction.type),
    filter(() => Router.query[QUERY_PARAM_TAB] === TAB_WATCH),
    filter(() => !!dragAndDropEndSelector(state$.value)?.over?.id),
    mergeMap(() => {
      const { active, over } = dragAndDropEndSelector(state$.value);

      const videos = videosSelector(state$.value);

      const channel = getChannelFromStore(state$.value);
      let playlist = null;

      if (channel) {
        const playlistsEntities = watchesSelectors.playlistsEntitiesSelector(state$.value);
        playlist = playlistsEntities[channel.playlistId] ?? null;
      }

      const actions = [];

      const activeMetadata = active?.id ? parseDndId(active.id) : {};
      const overMetadata = over?.id ? parseDndId(over.id) : {};

      // dnd channels
      // metadataObject = { type, watchId, channelId, itemIndex }
      if (
        activeMetadata.type === DND_PLAYLIST_TYPE &&
        overMetadata.type === DND_PLAYLIST_TYPE &&
        activeMetadata.watchId === overMetadata.watchId
      ) {
        const watches = watchesSelectors.watchesSelector(state$.value);
        const newWatches = watches?.map((watch) => {
          if (watch.id === +activeMetadata.watchId) {
            const watchChannels = reorderVideos(watch.watchChannels, activeMetadata.itemIndex, overMetadata.itemIndex);

            return {
              ...watch,
              watchChannels,
            };
          }

          return watch;
        });

        actions.push(
          of(setWatchesAction(newWatches)),
          of(
            updateChannelAction({
              id: +activeMetadata.channelId,
              watchId: +activeMetadata.watchId,
              order: +overMetadata.itemIndex + 1,
            }),
          ),
        );
      }

      // dnd videos inside playlist
      // metadataObject = { type, channelId, distributionId, itemIndex }
      if (activeMetadata.type === DND_PLAYLIST_VIDEO_TYPE && overMetadata.type === DND_PLAYLIST_VIDEO_TYPE) {
        const items = reorderVideos(playlist?.clips ?? [], activeMetadata.itemIndex, overMetadata.itemIndex);

        actions.push(
          of(
            updatePlaylistAction({
              playlistId: channel.playlistId,
              clips: items ?? [],
              publisherId: playlist.publisherId,
            }),
          ),
        );
      }

      // dnd video from search results to channel
      // metadataObject = { type, videUid, distributionId, itemIndex }
      if (activeMetadata.type === DND_MAIN_LIST_OF_VIDEO_TYPE && overMetadata.type === DND_PLAYLIST_VIDEO_TYPE) {
        const targetClip = videos[activeMetadata.itemIndex];
        if (playlist?.clips?.includes(targetClip?.distributionId)) {
          return of(
            showNotificationAction({
              type: TYPE_ERROR,
              message: 'The video is already in the channel',
            }),
          );
        }

        const newClips = [...(playlist?.clips ?? [])];
        newClips.splice(overMetadata.itemIndex, 0, targetClip.distributionId);

        actions.push(
          of(
            updatePlaylistAction({
              playlistId: channel.playlistId,
              clips: newClips,
              publisherId: playlist.publisherId,
            }),
          ),
        );
      }

      return concat(...actions);
    }),
  );
