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

import * as watchesSelectors from '../selectors';
import {
  getNextWatchesAction,
  getWatchesAction,
  setMrssOnlyAction,
  setNextWatchesAction,
  setPublisherAction,
  setSearchAction,
  setSortByAction,
  setSortOrderAction,
  setStatusAction,
  setVerticalOnlyAction,
  setWatchesAction,
  setWatchesPaginationInfoAction,
} from '../slices';
import { gqlRequest } from '@/modules/@common/request';
import { getToken } from '@/modules/@common/token/helpers';

const queryGQL = `
  query WatchesQuery(
    $page: Int,
    $pageSize: Int,
    $publisherIds: [Int],
    $search: String,
    $status: Int,
    $mrssOnly: Boolean,
    $verticalOnly: Boolean,
    $sortBy: String,
    $sortOrder: String
  ) {
    watches(
      page: $page,
      pageSize: $pageSize,
      publisherIds: $publisherIds,
      search: $search,
      status: $status,
      mrssOnly: $mrssOnly,
      verticalOnly: $verticalOnly,
      sortBy: $sortBy,
      sortOrder: $sortOrder
    ) {
      recordsTotal
      page
      pageSize
      records {
        id
        title
        status
        environment
        folderName
        createdAt
        createdBy
        updatedAt
        updatedBy
        watchChannels {
          id
          title
          size
          design
          playlistId
          createdAt
          createdBy
          updatedAt
          updatedBy
          MRSSForExport
        }
        player {
          publisherId
        }
      }
    }
  }
`;

export default (action$, state$) =>
  action$.pipe(
    ofType(
      getWatchesAction.type,
      getNextWatchesAction.type,
      setPublisherAction.type,
      setSearchAction.type,
      setSortByAction.type,
      setSortOrderAction.type,
      setStatusAction.type,
      setMrssOnlyAction.type,
      setVerticalOnlyAction.type,
    ),
    debounce((action) => timer(action.type === setSearchAction.type ? 1000 : 0)),
    filter(() => !!getToken()),
    switchMap(({ type }) => {
      const page = watchesSelectors.pageSelector(state$.value);
      const pageSize = watchesSelectors.pageSizeSelector(state$.value);
      const publisher = watchesSelectors.publisherSelector(state$.value);
      const search = watchesSelectors.searchSelector(state$.value);
      const status = watchesSelectors.statusSelector(state$.value);
      const mrssOnly = watchesSelectors.mrssOnlySelector(state$.value);
      const verticalOnly = watchesSelectors.verticalOnlySelector(state$.value);
      const sortBy = watchesSelectors.sortBySelector(state$.value);
      const sortOrder = watchesSelectors.sortOrderSelector(state$.value);

      const variables = {
        page: type === getNextWatchesAction.type ? page + 1 : 1,
        pageSize,
        search,
        sortBy,
        sortOrder: sortOrder.toLowerCase(),
      };

      if (publisher?.id) {
        variables.publisherIds = [publisher.id];
      }

      if (status) {
        variables.status = status.value;
      }

      if (mrssOnly) {
        variables.mrssOnly = mrssOnly;
      }

      if (verticalOnly) {
        variables.verticalOnly = verticalOnly;
      }

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

          if (!response.errors.length) {
            const {
              data: { watches },
            } = response;

            if (type === getNextWatchesAction.type) {
              actions.push(of(setNextWatchesAction(watches.records)));
            } else {
              actions.push(of(setWatchesAction(watches.records)));
            }

            actions.push(
              of(
                setWatchesPaginationInfoAction({
                  page: watches.page,
                  pageSize: watches.pageSize,
                  recordsTotal: watches.recordsTotal,
                }),
              ),
            );
          }

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

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