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

import { PCN_POST_VIDEO } from '@/modules/@common/acl/constants';
import { TYPE_ERROR } from '@/modules/@common/notify/constants';

import * as selectors from '../../selectors';
import {
  addToUploadQueueAction,
  clearAction,
  setS3LinksAction,
  startUploadAction,
  startUploadFromQueueAction,
} from '../../slices';
import { clearAction as clearCcFilesModuleBeforeUnmount } from '@/modules/@common/ccFiles/redux/slices';
import { gqlRequest } from '@/modules/@common/request';
import { hasPermission } from '@/modules/@common/user/helpers';
import { getUserPermissionsSelector } from '@/modules/@common/user/redux/selectors';
import { showNotificationAction } from '@/modules/layout/redux/slices';

const queryGQL = `
  query Query($name: String, $filename: String, $thumbnail: String, $ccFiles: [String], $contentOwnerId: Float!, $refId: String) {
    S3UploadLink(name: $name, filename: $filename, thumbnail: $thumbnail, ccFiles: $ccFiles, contentOwnerId: $contentOwnerId, refId: $refId) {
      uploadUrl
      downloadUrl
      thumbnailUploadUrl
      thumbnailDownloadUrl
      ccFiles {
        uploadUrl
        downloadUrl
        isUploaded
      }
    }
  }
`;

export default (action$, state$) =>
  action$.pipe(
    ofType(startUploadAction.type),
    filter(() => hasPermission(PCN_POST_VIDEO, getUserPermissionsSelector(state$.value))),
    switchMap(() => {
      const videoUrl = selectors.videoUrlSelector(state$.value);
      const title = selectors.titleSelector(state$.value);
      const video = selectors.videoSelector(state$.value);
      const csvFile = selectors.csvFileSelector(state$.value);
      const thumbnail = selectors.thumbnailSelector(state$.value);
      const owner = selectors.ownerSelector(state$.value);
      const ccFiles = selectors.ccFilesSelector(state$.value);
      const refId = selectors.refIdSelector(state$.value);
      const queue = selectors.queueSelector(state$.value);

      const filename = (video && video.name) || (csvFile && csvFile.name);
      const thumbnailName = thumbnail && thumbnail.name;
      const contentOwnerId = owner && owner.value;
      const ccFilesData = ccFiles.map((ccFile) => ccFile?.fileObject?.name);

      const actions = [];

      // check title is uniq
      const itemsInQueue = Object.values(queue);
      const hasTitleInQueue = itemsInQueue.some((q) => q.title === title && !q.csvFile);

      if (hasTitleInQueue) {
        return concat(
          of(
            showNotificationAction({
              type: TYPE_ERROR,
              message: 'The video title already exists. Please enter a new one',
            }),
          ),
        );
      }

      if (filename || thumbnail || ccFilesData.length) {
        const stream$ = gqlRequest({
          query: queryGQL,
          variables: {
            contentOwnerId,
            thumbnail: thumbnailName,
            ccFiles: ccFilesData,
            filename,
            name: title,
            refId,
          },
        }).pipe(
          switchMap(({ data, errors }) => {
            const actions$ = [];

            if (!errors.length && data.S3UploadLink) {
              const s3uploadParams = { ...data.S3UploadLink };

              actions$.push(
                of(
                  setS3LinksAction({
                    key: !csvFile ? 'uploadVideo' : 'uploadCsv',
                    s3uploadParams,
                  }),
                ),
                of(addToUploadQueueAction()),
                of(clearAction()),
                of(clearCcFilesModuleBeforeUnmount()),
                of(startUploadFromQueueAction()),
              );
            }

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

        actions.push(stream$);
      } else if (videoUrl) {
        actions.push(
          of(addToUploadQueueAction()),
          of(clearAction()),
          of(clearCcFilesModuleBeforeUnmount()),
          of(startUploadFromQueueAction()),
        );
      }

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