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

import { EDITORIAL_PAGE } from '@/modules/@common/router/constants';
import { VIDEO_STATE_PROCESSING } from '@/modules/editorial/editorialSearch/constants/searchFilter';

import { videosSelector } from '../selectors';
import { videosAction, videosChangeProcessingStatusMonitoringAction } from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { selectedVideoSelector } from '@/modules/editorial/editorialVideoDetails/redux/selectors';
import { reloadSelectedVideoAction } from '@/modules/editorial/editorialVideoDetails/redux/slices';

import videosQuery from '@/modules/@common/gql/queries/videos';

const MONITORING_DELAY = 5000;

const getResponse = ({ data: { videoSearch }, errors }) => ({ videoSearch, errors });

export default (action$, state$) =>
  action$.pipe(
    ofType(videosChangeProcessingStatusMonitoringAction.type),
    filter(() => Router.pathname === EDITORIAL_PAGE.path),
    debounceTime(MONITORING_DELAY),
    switchMap(() => {
      const videos = videosSelector(state$.value);
      const selectedVideo = selectedVideoSelector(state$.value);
      const videosIdsWithProcessingStatus = videos
        .filter((video) => video.status === VIDEO_STATE_PROCESSING)
        .map((video) => video.uid);
      const actions = [];

      if (videosIdsWithProcessingStatus.length) {
        const stream$ = gqlRequest({
          query: videosQuery,
          variables: {
            videoIds: videosIdsWithProcessingStatus,
            size: videosIdsWithProcessingStatus.length,
          },
        }).pipe(
          switchMap((response) => {
            const streamActions = [];

            if (!response.errors.length) {
              const { videoSearch } = getResponse(response);
              const videosForUpdate = videoSearch.videos.filter((video) => video.status !== VIDEO_STATE_PROCESSING);

              if (videosForUpdate.length) {
                const listOfVideos = videos.map((video) => {
                  const videoForUpdate = videosForUpdate.find((v) => v.uid === video.uid);

                  if (videoForUpdate) {
                    return videoForUpdate;
                  }

                  return video;
                });

                const hasOpenedVideo =
                  selectedVideo?.uid && videosForUpdate.find((video) => video.uid === selectedVideo.uid);

                streamActions.push(of(videosAction(listOfVideos)));

                if (hasOpenedVideo) {
                  streamActions.push(of(reloadSelectedVideoAction()));
                }
              }
            }

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

        actions.push(stream$);
      }

      actions.push(of(videosChangeProcessingStatusMonitoringAction()));

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