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

import { TYPE_SUCCESS } from '@/modules/@common/notify/constants';
import {
  FORM_DOWNLOAD_STATUS_RETRY,
  FORM_DOWNLOAD_STATUS_START,
  FORM_MAX_DOWNLOAD_TRY_REQUESTS,
} from '@/modules/forms/constants';

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

const query = `
  query DownloadFormData(
    $formId: Int!
    $startDate: String!
    $bucketConfig: BucketConfigInputType
  ) {
    downloadFormData(
      formId: $formId
      startDate: $startDate
      bucketConfig: $bucketConfig
    ) {
     fileName
     downloadUrl
     bucketConfig {
       bucket
       path
     }
    }
  }
`;

const getResponse = ({ data: { downloadFormData } }) => downloadFormData;

export default (action$, state$) =>
  action$.pipe(
    ofType(downloadFormDataAction.type),
    switchMap(({ payload }) => {
      const { formId, startDate, bucketConfig = null, status } = payload;
      const actions = [];

      const showProgressBar = (isFormDownloadInProgress) => setFieldAction({ isFormDownloadInProgress });

      if (status === FORM_DOWNLOAD_STATUS_START) {
        actions.push(
          of(showProgressBar(true)),
          of(
            setFieldAction({
              formDownloadTryRequestCounter: 1,
            }),
          ),
        );
      }

      const stream$ = gqlRequest({
        query,
        variables: {
          formId,
          startDate: dayjs(startDate).format('YYYY-MM-DD'),
          bucketConfig,
        },
      }).pipe(
        switchMap((response) => {
          if (!response.errors.length) {
            const formDownloadTryRequestCounter = selectors.formDownloadTryRequestCounterSelector(state$.value);
            const { fileName, downloadUrl, bucketConfig: bucketConfigFromResponse } = getResponse(response);
            const responseActions = [];

            const isFormDataNotFound = !downloadUrl && !bucketConfigFromResponse;
            const isTryReplyDownload =
              !downloadUrl &&
              !!bucketConfigFromResponse &&
              formDownloadTryRequestCounter <= FORM_MAX_DOWNLOAD_TRY_REQUESTS;
            const isReadyToDownload = !!downloadUrl;
            const isDownloadTryRequestOver = formDownloadTryRequestCounter >= FORM_MAX_DOWNLOAD_TRY_REQUESTS;

            switch (true) {
              case isFormDataNotFound: {
                responseActions.push(
                  of(
                    showNotificationAction({
                      type: TYPE_SUCCESS,
                      message: 'Form response is empty',
                    }),
                  ),
                  of(showProgressBar(false)),
                );
                break;
              }
              case isTryReplyDownload: {
                responseActions.push(
                  of(
                    setFieldAction({
                      formDownloadTryRequestCounter: formDownloadTryRequestCounter + 1,
                    }),
                  ),
                  of(
                    downloadFormDataAction({
                      formId,
                      startDate,
                      bucketConfig: bucketConfigFromResponse,
                      status: FORM_DOWNLOAD_STATUS_RETRY,
                    }),
                  ),
                );
                break;
              }
              case isDownloadTryRequestOver: {
                responseActions.push(
                  of(setFieldAction({ shouldShowDownloadTryRequestOverConfirm: true })),
                  of(showProgressBar(false)),
                  of(
                    sendFormReportToUserEmailAction({
                      formId,
                      bucketConfig,
                      startDate,
                    }),
                  ),
                );
                break;
              }
              case isReadyToDownload: {
                const link = document.createElement('a');
                link.href = downloadUrl;
                link.download = fileName;
                link.click();

                responseActions.push(of(showProgressBar(false)));

                break;
              }
              default:
                break;
            }

            return concat(...responseActions);
          }

          return EMPTY;
        }),
      );

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