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

import {
  fallbackOnlySelector,
  pageSelector,
  pageSizeSelector,
  playersSelector,
  playlistIdSelector,
  playlistsSelector,
  publisherSelector,
  searchSelector,
  sortBySelector,
  sortOrderSelector,
  statusSelector,
} from '../../selectors';
import {
  getPlaylistsAction,
  setIsLoadingAction,
  setPageAction,
  setPlaylistsAction,
  setRecordsTotalAction,
} from '../../slices';
import { gqlRequest } from '@/modules/@common/request';
import { getToken } from '@/modules/@common/token/helpers';
import { getPublisherIdsSelector } from '@/modules/@common/user/redux/selectors';

const queryGQL = `
  query getPlaylists(
    $publisherIds: [Int],
    $type: String,
    $page: Int,
    $pageSize: Int,
    $searchText: String,
    $status: String,
    $fallbackOnly: Boolean,
    $sortBy: String,
    $sortOrder: String
  ) {
    getPlaylists(
      publisherIds: $publisherIds,
      type: $type,
      page: $page,
      pageSize: $pageSize,
      searchText: $searchText,
      status: $status,
      fallbackOnly: $fallbackOnly,
      sortBy: $sortBy,
      sortOrder: $sortOrder) {
      records {
        id
        playerId
        status
        isPrefix
        name
        url
        createdAt
        updatedAt
        createdBy
        updatedBy
        clips
        shuffle
        playerAlias
        widgetName
        pubName
        publisherId
        publisherName
        playerAspectRatio
        isFallback
        
        includeSponsoredContent,
        frequency,
        supplyTagId,
        supplyTagName,
      }
      recordsTotal
      page
      pageSize
    }
  }
`;

export default (action$, state$) =>
  action$.pipe(
    ofType(getPlaylistsAction.type),
    debounceTime(500),
    filter(() => !!getToken()),
    filter(() => !!getPublisherIdsSelector(state$.value)?.length || publisherSelector(state$.value)),
    switchMap(({ payload: { isNext = false } = {} }) => {
      const pageSize = pageSizeSelector(state$.value);
      const players = playersSelector(state$.value);
      const prevPage = pageSelector(state$.value);
      const publisher = publisherSelector(state$.value);
      const search = searchSelector(state$.value);
      const status = statusSelector(state$.value);
      const fallbackOnly = fallbackOnlySelector(state$.value);
      const sortBy = sortBySelector(state$.value);
      const sortOrder = sortOrderSelector(state$.value);

      const variables = {
        type: 'EDITORIAL',
        searchText: search,
        sortBy: sortBy.toLowerCase(),
        sortOrder: sortOrder.toLowerCase(),
        page: isNext ? prevPage + 1 : 1,
        pageSize,
        isNew: true,
      };

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

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

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

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

          if (!errors.length) {
            const { records, recordsTotal } = data.getPlaylists;

            const newPlaylists = records.map((playlist) => {
              const { status: playlistStatus, playerId, createdAt: createdDate, updatedAt: updatedDate } = playlist;

              // convert from dayjs to milliseconds
              const createdAt = dayjs(createdDate).valueOf();
              const updatedAt = updatedDate ? dayjs(updatedDate).valueOf() : updatedDate;

              const player = players.find((item) => item?.id === playerId);

              return {
                ...playlist,
                createdAt,
                updatedAt,
                isStatusUpdateDisabled: !playlistStatus && !player,
                displayEmbedCode: player?.displayEmbedCode,
              };
            });

            const playlistId = playlistIdSelector(state$.value);
            const oldPlaylists = playlistsSelector(state$.value);

            if (playlistId) {
              // If you open a playlist, then go to the playlist list and quickly open another playlist,
              // the store (state.playlists) gets updated and overwrites
              // the video values (state.playlists: [{ ...playlistInfo, videos: [] }])
              const playlistOld = oldPlaylists.find((playlist$) => playlist$.id === playlistId);
              const playlistNewIndex = newPlaylists.findIndex((playlist$) => playlist$.id === playlistId);
              if (playlistOld && playlistNewIndex !== -1) {
                newPlaylists.splice(playlistNewIndex, 1, { ...newPlaylists[playlistNewIndex], ...playlistOld });
              }
            }

            actions.push(
              of(setIsLoadingAction(false)),
              of(setPlaylistsAction(isNext ? [...oldPlaylists, ...newPlaylists] : newPlaylists)),
              of(setPageAction(variables.page)),
              of(setRecordsTotalAction(recordsTotal)),
            );
          }

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

      return concat(of(setIsLoadingAction(true)), stream$);
    }),
  );
