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

import { TYPE_ERROR, TYPE_SUCCESS } from '@/modules/@common/notify/constants';

import { DestinationType } from '../../types';

import { addPublishEntriesAction, getPublishEntriesAction } from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { showNotificationAction } from '@/modules/layout/redux/slices';

import type { RootState } from '@/modules/@common/store/store';

const queryGQL = `
  mutation createPublishEntry($destinations: [PublishEntryInputType]) {
    createPublishEntry(destinations: $destinations) {
        data {
          id
          status
        }
    }
  }
`;

const epic: Epic<Action, Action, RootState> = (action$) =>
  action$.pipe(
    filter(
      (action): action is ReturnType<typeof addPublishEntriesAction> => action.type === addPublishEntriesAction.type,
    ),
    switchMap((action) => {
      const { destinations, videoId } = action.payload;

      const paramsToSend = destinations
        .filter((dest: DestinationType) => dest.checked && !dest.published && dest.targetId && dest.targetName)
        .map((dest: DestinationType) => ({
          videoId,
          platform: dest.type,
          accountId: dest.id,
          target: {
            id: dest.targetId,
            name: dest.targetName,
            type: dest.targetType.toUpperCase(),
          },
          viewability: dest.visibility,
          settings: dest.settings,
          postText: dest.postText,
        }));

      const stream$ = gqlRequest({
        query: queryGQL,
        variables: {
          destinations: [...paramsToSend],
        },
      }).pipe(
        switchMap(({ errors }) => {
          const actions = [];

          if (!errors.length) {
            actions.push(
              of(getPublishEntriesAction(videoId)),
              of(
                showNotificationAction({
                  type: TYPE_SUCCESS,
                  message: 'Video published',
                }),
              ),
            );
          }

          const corruptedDestinations = destinations.filter(
            (dest: DestinationType) => dest.checked && !dest.published && (!dest.targetId || !dest.targetName),
          );

          if (corruptedDestinations.length) {
            actions.push(
              of(
                showNotificationAction({
                  type: TYPE_ERROR,
                  message: `There are corrupted destinations (${corruptedDestinations.length})`,
                }),
              ),
            );
          }

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

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

export default epic;
