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

import { MAX_DOWNLOAD_TRY_REQUESTS, MONITORING_DELAY } from '../../constants';
import { TYPE_ERROR, TYPE_WARNING } from '@/modules/@common/notify/constants';

import * as selectors from '../selectors';
import { checkDownloadReportAction, setFieldAction } from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { showNotificationAction } from '@/modules/layout/redux/slices';

const MONITORING_STATUS = {
  PROCESSING: 'PROCESSING',
  DONE: 'DONE',
  ERROR: 'ERROR',
};

const query = `
  query CustomReportDownloadCheck(
    $reportId: Int!,
    $operationId: String!
  ) {
    customReportDownloadCheck(
      reportId: $reportId,
      operationId: $operationId
    ) {
       reportId
       operationId
       status
       message
       file
    }
  }
`;

export default (action$, state$) =>
  action$.pipe(
    ofType(checkDownloadReportAction.type),
    debounceTime(MONITORING_DELAY),
    filter(({ payload }) => payload.reportId && payload.operationId),
    switchMap(({ payload }) => {
      const state = state$.value;

      const downloadReportTryRequestCounter = selectors.downloadReportTryRequestCounterSelector(state);

      const stream$ = gqlRequest({
        query,
        variables: {
          reportId: payload.reportId,
          operationId: payload.operationId,
        },
      }).pipe(
        switchMap(({ data: { customReportDownloadCheck = {} }, errors }) => {
          if (!errors.length) {
            const { status, file, message } = customReportDownloadCheck;

            const isTryDownload =
              status === MONITORING_STATUS.PROCESSING && downloadReportTryRequestCounter < MAX_DOWNLOAD_TRY_REQUESTS;
            const isDownloadTryRequestOver = downloadReportTryRequestCounter >= MAX_DOWNLOAD_TRY_REQUESTS;

            switch (true) {
              case status === MONITORING_STATUS.DONE: {
                const link = document.createElement('a');
                link.href = file;
                link.download = payload.fileName;
                link.click();

                return concat(
                  of(
                    setFieldAction({
                      isDownloading: false,
                      downloadReportTryRequestCounter: 0,
                    }),
                  ),
                );
              }
              case isTryDownload: {
                return concat(
                  of(
                    checkDownloadReportAction({
                      reportId: payload.reportId,
                      operationId: payload.operationId,
                      fileName: payload.fileName,
                    }),
                  ),
                  of(
                    setFieldAction({
                      downloadReportTryRequestCounter: downloadReportTryRequestCounter + 1,
                    }),
                  ),
                );
              }
              case isDownloadTryRequestOver: {
                return concat(
                  of(
                    showNotificationAction({
                      type: TYPE_WARNING,
                      message: 'Download is taking too long. We will email the report to you instead',
                    }),
                  ),
                  of(
                    setFieldAction({
                      downloadReportTryRequestCounter: 0,
                      isDownloading: false,
                    }),
                  ),
                );
              }
              case status === MONITORING_STATUS.ERROR: {
                return concat(
                  of(
                    showNotificationAction({
                      type: TYPE_ERROR,
                      message,
                    }),
                  ),
                  of(
                    setFieldAction({
                      isDownloading: false,
                      downloadReportTryRequestCounter: 0,
                    }),
                  ),
                );
              }
              default: {
                return EMPTY;
              }
            }
          }

          return EMPTY;
        }),
      );

      return concat(stream$);
    }),
  );
