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_START, FORM_MAX_DOWNLOAD_TRY_REQUESTS } from '@/modules/forms/constants';

import { formDownloadProcessingNotificationKeySelector, formDownloadTryRequestCounterSelector } from '../selectors';
import { downloadFormDataAction, sendFormReportToUserEmailAction, setFieldAction } from '../slices';
import { closeNotifyAction } from '@/modules/@common/notify/redux/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, notificationKey = null) =>
        setFieldAction({
          isFormDownloadInProgress,
          formDownloadProcessingNotificationKey: notificationKey,
        });

      if (status === FORM_DOWNLOAD_STATUS_START) {
        const key = `${Math.random()}-${Math.random()}`;

        actions.push(
          of(showProgressBar(true, key)),
          of(
            showNotificationAction({
              type: TYPE_SUCCESS,
              message: 'Processing...',
              key,
              persist: 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 state = state$.value;
            const formDownloadProcessingNotificationKey = formDownloadProcessingNotificationKeySelector(state);
            const formDownloadTryRequestCounter = formDownloadTryRequestCounterSelector(state);

            const { fileName, downloadUrl, bucketConfig: bucketConfigFromResponse } = getResponse(response);
            const requestActions = [];

            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: {
                requestActions.push(
                  of(showProgressBar(false)),
                  of(closeNotifyAction(formDownloadProcessingNotificationKey)),
                  of(
                    showNotificationAction({
                      type: TYPE_SUCCESS,
                      message: 'Form response is empty',
                    }),
                  ),
                );
                break;
              }
              case isTryReplyDownload: {
                requestActions.push(
                  of(
                    setFieldAction({
                      formDownloadTryRequestCounter: formDownloadTryRequestCounter + 1,
                    }),
                  ),
                  of(
                    downloadFormDataAction({
                      formId,
                      startDate,
                      bucketConfig: bucketConfigFromResponse,
                    }),
                  ),
                );
                break;
              }
              case isDownloadTryRequestOver: {
                requestActions.push(
                  of(closeNotifyAction(formDownloadProcessingNotificationKey)),
                  of(showProgressBar(false)),
                  of(setFieldAction({ shouldShowDownloadTryRequestOverConfirm: true })),
                  of(
                    sendFormReportToUserEmailAction({
                      formId,
                      bucketConfig,
                      startDate,
                    }),
                  ),
                );
                break;
              }
              case isReadyToDownload: {
                const link = document.createElement('a');
                link.href = downloadUrl;
                link.download = fileName;
                link.click();

                requestActions.push(
                  of(showProgressBar(false)),
                  of(closeNotifyAction(formDownloadProcessingNotificationKey)),
                );
                break;
              }
              default:
                break;
            }

            return concat(...requestActions);
          }

          return EMPTY;
        }),
      );

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