import React, { useCallback, useEffect } from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { withReducer } from '../../app/core/with-reducer';
import { withEpics } from '../../app/core/with-epics';
import { Track } from '../components';
import reducer, { ACTION } from '../reducer';
import * as epics from '../epics';
import { fp as _ } from '../../common/utils/fp';
import { ContextStatics, ContextTrack, ContextVisibility } from '../contexts';
import {
  makeIsStarredSelector,
  makeRefreshSelector,
  makeStaticsExtendedSelector,
  makeVisibilitySelector,
  makeUrlAppleDataSelector,
  makeUrlSpotifyDataSelector,
  makeTrackSelector,
  makeInitedSelector,
  makeCurrentDistributorSelector,
} from '../selectors';
import { makeLastStreamDateShortSelector } from '../../common/selectors/stream-latest-date/stream-latest-date-selectors';
import {
  makeMarketSelector,
  makeRoutingParamsSelector,
  makeStarredSelector,
} from '../../common/selectors';
import { withErrorBoundary } from '../../common/hoc/with-error-boundary';
import { withNavigationSync } from '../../common/hoc/with-navigation-sync';
import { TrackFlush } from '../services';
import {
  TState,
  TVisibilityConfig,
  TNavParams,
  TStatics,
  TUrlApple,
  TUrlSpotify,
  TRoute,
} from '../types';
import {
  TMarketUndef,
  TRouteParams,
  TState as TCommonState,
} from '../../common/types';
import { useNavKeyMap } from '../../common/hooks/use-nav-key-map';
import { ROUTES } from '../../app/constants';
import { composeContexts } from '../../common/utils/react-better-context';
import { ACTION as COMMON_ACTION } from '../../common/reducer';
import { PAGES, updatePageMeta } from '../../analytics';
import { withStarred } from '../../common/submodules/starring-tracks/hoc/with-starred';
import { withStreamLatestDate } from '../../common/hoc/with-stream-latest-date';
import { withStarredPlaylists } from '../../common/submodules/starring-playlists/hoc/with-starred-playlists';
import {
  TToggleStarred,
  TToggleStarredPayload,
} from '../../common/submodules/starring-tracks/types';
import { makeVisibilityConfigSelector as makeVisibilityChartsSelector } from '../../track-charts/selectors';
import { makeVisibilityConfigSelector as makeVisibilityMarketsSelector } from '../../track-markets/selectors';
import { makeVisibilityConfigSelector as makeVisibilityPlaylistsSelector } from '../../track-playlists/selectors';
import {
  makeNmfDataSelector,
  makeHhDataSelector,
} from '../../track-nmf/selectors';
import { TVisibility as TVisibilityTrackCharts } from '../../track-charts/types';
import { TVisibility as TVisibilityTrackMarkets } from '../../track-markets/types';
import { TVisibility as TVisibilityTrackPlaylists } from '../../track-playlists/types';
import { TState as TStateNmf } from '../../track-nmf/types';
import {
  getNotificationSideEffectCooldown,
  NOTIFICATION_COOLDOWN_VARIANT,
} from '../../common/utils/notification-service';
import { TRACK_PAGE_SOURCES } from '../../analytics/constants';
import { EDistributor } from '../../common/constants';

type TStructured = {
  inited: TState['inited'];
  refreshing: TState['refresh'];
  visibility: TVisibilityConfig;
  visibilityCharts: TVisibilityTrackCharts;
  visibilityMarkets: TVisibilityTrackMarkets;
  visibilityPlaylists: TVisibilityTrackPlaylists;
  statics: TStatics | undefined;
  distributor: EDistributor;
  urlApple: TUrlApple | undefined;
  urlSpotify: TUrlSpotify | undefined;
  isStarred: boolean;
  market: TMarketUndef;
  lastStreamDate: string | null;
  routeParams?: TRouteParams;
  track: TState['track'];
  nmfData: TStateNmf['nmfData'];
  hhData: TStateNmf['hhData'];
  starred: TCommonState['starred'];
};
type TConnected = {
  getTrack: (data: TNavParams) => void;
  refresh: () => void;
  flush: () => void;
  toggleStarred: TToggleStarred;
  route: TRoute;
} & TStructured;
type TPropsExternal = {};

const mapStateToProps = createStructuredSelector<any, TStructured>({
  inited: makeInitedSelector(),
  track: makeTrackSelector(),
  refreshing: makeRefreshSelector(),
  visibility: makeVisibilitySelector(),
  visibilityCharts: makeVisibilityChartsSelector(),
  visibilityMarkets: makeVisibilityMarketsSelector(),
  visibilityPlaylists: makeVisibilityPlaylistsSelector(),
  statics: makeStaticsExtendedSelector(),
  distributor: makeCurrentDistributorSelector(),
  urlApple: makeUrlAppleDataSelector(),
  urlSpotify: makeUrlSpotifyDataSelector(),
  isStarred: makeIsStarredSelector(),
  market: makeMarketSelector(),
  lastStreamDate: makeLastStreamDateShortSelector(),
  routeParams: makeRoutingParamsSelector(),
  nmfData: makeNmfDataSelector(),
  hhData: makeHhDataSelector(),
  starred: makeStarredSelector(),
  //†prop
});
const mapDispatchToProps = {
  getTrack: ACTION.getTrack,
  refresh: ACTION.refresh,
  flush: ACTION.flush,
  toggleStarred: COMMON_ACTION.toggleStarred,
  //†action
};

// Uncomment to write componentDidMount hook
const Connected: React.FC<TConnected> = ({
  getTrack,
  flush,
  statics,
  distributor,
  urlApple,
  urlSpotify,
  ...rest
}) => {
  const { toggleStarred, track, inited, route } = rest;

  const toggleStarredExtended = useCallback(() => {
    toggleStarred(
      {
        ...track.data,
        starSource: TRACK_PAGE_SOURCES.Common,
      } as TToggleStarredPayload,
      {
        star: {
          onSuccess: () => {
            updatePageMeta({
              page: PAGES.Track.page,
              is_starred: true,
            });
          },
        },
        unstar: {
          onSuccess: () => {
            updatePageMeta({
              page: PAGES.Track.page,
              is_starred: false,
            });
          },
        },
      }
    );
  }, [track.data && _.path('isrc', track.data)]);

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

  useEffect(() => {
    return () => {
      if (
        getNotificationSideEffectCooldown() ===
        NOTIFICATION_COOLDOWN_VARIANT.track
      )
        return;
      return flush();
    };
  }, []);
  useEffect(() => {
    setTimeout(() => {
      if (
        getNotificationSideEffectCooldown() ===
        NOTIFICATION_COOLDOWN_VARIANT.track
      )
        return;
      getTrack(route.params!);
    });

    return () => {
      if (
        getNotificationSideEffectCooldown() ===
        NOTIFICATION_COOLDOWN_VARIANT.track
      )
        return;
      TrackFlush.next();
    };
  }, [route.params!.marketCode]);

  return composeContexts(
    [
      [
        ContextTrack,
        {
          track,
          inited,
        },
      ],
      [
        ContextStatics,
        {
          data: statics,
          urls: { apple: urlApple, spotify: urlSpotify },
          distributor,
        },
      ],
      [ContextVisibility, { visibility: rest.visibility }],
    ],
    <Track {...rest} toggleStarred={toggleStarredExtended} />
  );
};

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