import React, { useCallback, useEffect } from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { createStructuredSelector } from 'reselect';
import { withReducer } from '../../app/core/with-reducer';
import { withEpics } from '../../app/core/with-epics';
import { fp as _ } from '../../common/utils/fp';
import { Playlist } from '../components';
import reducer, { ACTION } from '../reducer';
import * as epics from '../epics';
import { withErrorBoundary } from '../../common/hoc/with-error-boundary';
import { withNavigationSync } from '../../common/hoc/with-navigation-sync';
import {
  makePlaylistVisibilityConfigSelector,
  makeRefreshSelector,
  makePlaylistExtendedSelector,
  makeGalleryCardDataSelector,
  makeTracklistExtendedSelector,
  makeTracklistVisibilityConfigSelector,
  makeTracklistsCardsDataSelector,
  makeTracklistsCardsVisibilitySelector,
  makeOfflineSelector,
} from '../selectors';
import {
  TGalleryCardData,
  TNavParams,
  TRootPlaylistState,
  TRoute,
  TState,
  TTracklistsCardsDataRes,
} from '../types';
import { NEntityInfinite, TEntityVisibility } from '../../common/types';
import { composeContexts } from '../../common/utils/react-better-context';
import {
  ContextHeader,
  ContextSlider,
  ContextTracklistsCards,
} from '../context';
import { useNavKeyMap } from '../../common/hooks/use-nav-key-map';
import { ROUTE_PARAMS, ROUTES } from '../../app/constants';
import { TTracklistExtended } from '../../playlist-tracklist-core/types';
import { withStreamLatestDate } from '../../common/hoc/with-stream-latest-date';
import { playlistVendor } from '../transducers';
import { ACTION as COMMON_ACTION } from '../../common/reducer';
import { withStarredPlaylists } from '../../common/submodules/starring-playlists/hoc/with-starred-playlists';
import { PAGES, updatePageMeta } from '../../analytics';
import {
  TToggleStarredPayload,
  TToggleStarredPlaylist,
} from '../../common/submodules/starring-playlists/types';
import { withStarred } from '../../common/submodules/starring-tracks/hoc/with-starred';
import {
  getNotificationSideEffectCooldown,
  NOTIFICATION_COOLDOWN_VARIANT,
} from '../../common/utils/notification-service';
import { MODULE_NAME } from '../constants';
import { EStarSourcePages } from '../../common/constants';

type TPropsExternal = {};
type TStructured = {
  playlistVisibility: TEntityVisibility;
  refreshing: boolean;
  offline: boolean;
  playlist: TState['playlist'];
  galleryCardData: TGalleryCardData;
  tracklist: TTracklistExtended;
  tracklistVisibility: TEntityVisibility;
  tracklistsCardsData: TTracklistsCardsDataRes;
  tracklistsCardsVisibility: TEntityVisibility;
};
type TConnected = TPropsExternal &
  TStructured & {
    getPlaylist: (data: TNavParams) => void;
    flush: () => void;
    refresh: () => void;
    setMarket: (market: string) => void;
    route: TRoute;
    getTracklist: NEntityInfinite.TEntityInfiniteGet;
    toggleStarred: TToggleStarredPlaylist;
  };

const mapStateToProps = createStructuredSelector<
  TRootPlaylistState,
  TStructured
>({
  playlistVisibility: makePlaylistVisibilityConfigSelector(),
  tracklistVisibility: makeTracklistVisibilityConfigSelector(),
  refreshing: makeRefreshSelector(),
  playlist: makePlaylistExtendedSelector(),
  galleryCardData: makeGalleryCardDataSelector(),
  tracklist: makeTracklistExtendedSelector(),
  tracklistsCardsData: makeTracklistsCardsDataSelector(),
  tracklistsCardsVisibility: makeTracklistsCardsVisibilitySelector(),
  offline: makeOfflineSelector(),
  //†prop
});
const mapDispatchToProps = {
  getPlaylist: ACTION.getPlaylist,
  getTracklist: ACTION.getTracklist,
  flush: ACTION.flush,
  refresh: ACTION.refresh,
  toggleStarred: COMMON_ACTION.toggleStarredPlaylist,
  setMarket: ACTION.setMarket,
  //†action
};

const Connected: React.FC<TConnected> = ({
  getPlaylist,
  flush,
  playlist,
  tracklistsCardsData,
  tracklistsCardsVisibility,
  setMarket,
  ...rest
}) => {
  const {
    toggleStarred,
    route,
    offline,
    playlistVisibility,
    galleryCardData,
    tracklistVisibility,
    tracklist,
  } = rest;
  const vendor = playlistVendor(route);

  const toggleStarredExtended = useCallback(() => {
    toggleStarred(
      {
        ...playlist.data,
        vendor,
        starSource: EStarSourcePages.Playlistpage,
      } as TToggleStarredPayload,
      {
        star: {
          onSuccess: () => {
            updatePageMeta({
              page: PAGES.Playlist.page,
              is_starred: true,
            });
          },
        },
        unstar: {
          onSuccess: () => {
            updatePageMeta({
              page: PAGES.Playlist.page,
              is_starred: false,
            });
          },
        },
      }
    );
  }, [playlist.data]);

  useNavKeyMap({ page: ROUTES.playlist, route });

  useEffect(() => {
    setTimeout(() => {
      if (
        getNotificationSideEffectCooldown() ===
        NOTIFICATION_COOLDOWN_VARIANT.playlist
      ) {
        return;
      }

      getPlaylist(route.params);
    });

    return () => {
      if (
        getNotificationSideEffectCooldown() ===
        NOTIFICATION_COOLDOWN_VARIANT.playlist
      )
        return;
      flush();
    };
  }, []);

  useEffect(() => {
    if (route.params[ROUTE_PARAMS.playlistrootMarket]) {
      setMarket(route.params[ROUTE_PARAMS.playlistrootMarket]);
    }
  }, [route.params[ROUTE_PARAMS.playlistrootMarket]]);

  return composeContexts(
    [
      [
        ContextSlider,
        {
          visibility: playlistVisibility,
          galleryCardData,
          vendor,
        },
      ],
      [
        ContextHeader,
        {
          entity: playlist,
          playlistVisibility,
          tracklistVisibility,
          vendor,
          offline,
        },
      ],
      [
        ContextTracklistsCards,
        {
          tracklistsCardsData,
          tracklist,
          tracklistVisibility,
          visibility: tracklistsCardsVisibility,
          vendor,
        },
      ],
    ],
    <Playlist {...rest} toggleStarred={toggleStarredExtended} />
  );
};

export default compose(
  _.hoistStatics(Playlist),
  withReducer(MODULE_NAME, reducer),
  withEpics(MODULE_NAME, epics),
  withErrorBoundary(MODULE_NAME),
  withNavigationSync(),
  withStarred,
  withStarredPlaylists,
  withStreamLatestDate,
  connect(
    mapStateToProps,
    mapDispatchToProps
  )
)(Connected) as React.FC<TPropsExternal>;
