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

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

import { playerSelector, publisherInfoSelector } from '../selectors';
import { getPlayerConfigAction, getTmPlaylistAction, updateLiveEventFormAction } from '../slices';
import { getDirtyEvalObjectFromString, getPlayerConfigCdnEndpoint } from '@/modules/@common/PlayerWidget/helpers';
import { parseErrorMessage } from '@/modules/@common/request';
import { showNotificationAction } from '@/modules/layout/redux/slices';

export default (action$, state$) =>
  action$.pipe(
    ofType(getPlayerConfigAction.type),
    filter((action) => {
      const { player: actionPlayer, publishers: actionPublisher } = action?.payload || {};
      const statePlayer = playerSelector(state$.value);
      const statePublisher = publisherInfoSelector(state$.value);

      const player = actionPlayer || statePlayer;
      const publisher = actionPublisher || statePublisher;

      return player && publisher;
    }),
    switchMap((action) => {
      const { player: actionPlayer, publishers: actionPublisher } = action?.payload || {};
      const statePlayer = playerSelector(state$.value);
      const statePublisher = publisherInfoSelector(state$.value);

      const player = actionPlayer || statePlayer?.name;
      const publisher = actionPublisher || statePublisher?.slug;

      // TODO: try to replace xmlhttprequest into rxjs ajax
      const stream$ = defer(() =>
        new Promise((resolve) => {
          const url = getPlayerConfigCdnEndpoint(publisher, player);
          const xhr = new XMLHttpRequest();
          xhr.open('GET', url, true);
          xhr.send();
          xhr.onload = () => {
            const succeeded = xhr.status === 200;

            resolve({
              data: succeeded ? xhr.responseText : null,
              errors: succeeded ? [] : [new Error(`Cannot find file: \n${url}`)],
            });
          };
        }).then((data) => data),
      ).pipe(
        switchMap(({ data, errors }) => {
          const actions = [];

          if (!errors.length) {
            actions.push(
              of(
                updateLiveEventFormAction({
                  playerConfig: getDirtyEvalObjectFromString(data),
                }),
              ),
            );
            if (!actionPlayer) {
              actions.push(of(getTmPlaylistAction()));
            }
          } else {
            const errorMessage = parseErrorMessage(errors[0]);

            actions.push(
              of(
                showNotificationAction({
                  type: TYPE_ERROR,
                  message: errorMessage,
                }),
              ),
            );
          }

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

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