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

import {
  getDataAction,
  setAction as setActionTagLog,
  updateSummaryTagsAction,
  updateVideoVerificationStateAction,
} from '../slices';
import { iabFlatToTree } from '@/modules/@common/iab/helpers';
import { gqlRequest } from '@/modules/@common/request';
import { selectedVideoSelector } from '@/modules/editorial/aiWorkbench/AiWorkbench/redux/selectors';
import { setAction } from '@/modules/editorial/aiWorkbench/AiWorkbench/redux/slices';
import { videosSelector } from '@/modules/editorial/editorialSearchResults/redux/selectors';
import { videosAction } from '@/modules/editorial/editorialSearchResults/redux/slices';

import queryVideoUpdateGQL from '@/modules/@common/gql/queries/videoUpdate';

const DELAY = 500;

export default (action$, state$) =>
  action$.pipe(
    ofType(updateSummaryTagsAction.type, updateVideoVerificationStateAction.type),
    debounceTime(DELAY),
    switchMap((action) => {
      const videos = videosSelector(state$.value);
      const selectedVideo = selectedVideoSelector(state$.value);
      const { payload: updateVideo } = action;

      // optimistic update
      const forUpdateVideo = { ...updateVideo };
      if (forUpdateVideo.iab) {
        forUpdateVideo.iab = {
          data: JSON.stringify({
            categories: iabFlatToTree(updateVideo.iab),
          }),
        };
      }

      const videosOptimisticUpdate = videos.map((originalVideo) => {
        if (originalVideo.uid === selectedVideo.uid) {
          return { ...originalVideo, ...forUpdateVideo };
        }

        return originalVideo;
      });

      const selectedVideoOptimisticUpdate = {
        ...selectedVideo,
        ...forUpdateVideo,
      };

      const stream$ = gqlRequest({
        query: queryVideoUpdateGQL,
        variables: {
          id: selectedVideo.uid,
          video: {
            ...updateVideo,
            updateClip: true,
          },
        },
      }).pipe(
        switchMap(({ data, errors }) => {
          const actions = [];

          if (!errors.length) {
            const updatedVideoList = videos.map((originalVideo) =>
              originalVideo.uid === selectedVideo.uid ? { ...originalVideo, ...data.videoUpdate } : originalVideo,
            );

            actions.push(
              of(videosAction(updatedVideoList)),
              of(setAction({ selectedVideo: { ...selectedVideo, ...data.videoUpdate } })),
            );

            if (action.type === updateSummaryTagsAction.type) {
              actions.push(of(getDataAction()));
            }
          }

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

      return concat(
        of(setAction({ selectedVideo: selectedVideoOptimisticUpdate })),
        of(videosAction(videosOptimisticUpdate)),
        of(setActionTagLog({ isLoading: false })),
        stream$,
      );
    }),
  );
