import React, { memo, useCallback } from 'react';
import { Dimensions, Platform } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { Undefinable } from 'tsdef';
import { RefreshableView } from '../../common/components/refreshable-view';
import { ViewLoadFailed } from '../../common/components/view-load-failed';
import { ViewNetworkFailed } from '../../common/components/view-network-failed';
import { Skeleton } from './skeleton';
import { SBox } from '../../common/s-components/layout/s-box';
import { SKeyboardAvoidingView } from '../../common/s-components/s-keyboard-avoiding-view';
import { addSafeArea, formatStreamDigit } from '../../common/transducers';
import {
  TActiveVisibilityConfig,
  TFilterConfig,
  // TNavigation,
  TPlaylistsOption,
  TState,
} from '../types';
import {
  NEntityInfinite,
  NSelect,
  TRefreshableRenderer,
  TRoute,
} from '../../common/types';
import { Header } from './header';
import { SortBlock } from '../../playlist-tracklist-core/components/sort-block';
import { DATE_RANGES, FETCH_TYPE } from '../../common/constants';
import { theme } from '../../app/theme';
import { Arc } from '../../common/components/arc';
import { List } from './list';
import { fp as _ } from '../../common/utils/fp';
import { SImage } from '../../common/s-components/s-image';
// import { SkeletonSorting } from '../../playlist-placement/components/skeleton-sorting';
// import { RefillingIndicator } from '../../common/components/refilling-indicator';
import { TState as TTrackState } from '../../track/types';
import { SHeaderGradient } from '../../track/s-components/s-header-gradient';
import { RefillingIndicator } from '../../common/components/refilling-indicator';
import { Portal } from '../../common/utils/portal/portal';
import { SwipeablePopup } from '../../common/components/bottom-sheet/swipeable-popup';
import { PopupSelector } from '../../common/components/popup-selector/popup-selector';
import { openPopupByVariant } from '../../common/utils/keyboard-service';
import { PlaylistsInfo } from './playlists-info';
import {
  ACTIVE_TAB,
  PLAYLISTS_POPUP_ID,
  PLAYLISTS_SORTING_POPUP_ID,
  SORTING_CURRENT_APPLE_OPTIONS,
  SORTING_CURRENT_SPOTIFY_OPTIONS,
  SORTING_PAST_APPLE_OPTIONS,
  SORTING_PAST_SPOTIFY_OPTIONS,
} from '../constants';
import { ViewEmptySearch } from './view-empty-search';
import { InfoPlaylists } from './info-playlists';
import {
  onPlaylistsCurrentPastSelected,
  onPlaylistsFilteringApplied,
  onPlaylistsSortingApplied,
} from '../../analytics';
import { LoadingOverlay } from '../../common/components/loading-overlay';
import { ROUTE_PARAMS, ROUTES } from '../../app/constants';
import { SSortingText } from '../s-components/s-sorting-text';
import { useNanoId } from '../../common/hooks/use-nano';

const maxHeight = addSafeArea(153);
const { height: DEVICE_HEIGHT } = Dimensions.get('window');

type TProps = {
  // navigation: TNavigation;
  refreshing: boolean;
  refresh: () => void;
  activeVisibility: TActiveVisibilityConfig;
  getData: NEntityInfinite.TEntityInfiniteGet;
  getSettings: NEntityInfinite.TEntityInfiniteGet;
  config: TState['config'];
  trackData: TTrackState['track'];
  isFailed: boolean;
  playlistOptions: TPlaylistsOption[];
  setConfig: (config: TState['config']) => void;
  current: TState['current'];
  past: TState['past'];
  categoryOptions: NSelect.TOption[];
  market: Undefinable<string>;
  isDirtySorting: boolean;
  route: TRoute;
};

export const Playlists: React.FC<TProps> = memo(props => {
  const {
    config,
    activeVisibility,
    isFailed,
    isDirtySorting,
    past,
    current,
    route,
    trackData,
    playlistOptions,
    setConfig,
    getData,
    getSettings,
    categoryOptions,
    refreshing,
    refresh,
  } = props;

  const id = useNanoId();

  const renderOffline = () => {
    return (
      <SBox position="relative" flex={1} pt={29}>
        <ViewNetworkFailed verticalOffset={35} />
      </SBox>
    );
  };

  const renderFailedToLoad = () => {
    const { vendor } = config;
    const isSpotify = vendor === 'spotify';
    const isApple = vendor === 'apple';

    return (
      <ViewLoadFailed
        variant="track-playlists"
        vendor={isSpotify ? 'Spotify' : isApple ? 'Apple Music' : 'Amazon'}
        verticalOffset={-22}
      />
    );
  };

  const renderHeader: TRefreshableRenderer = useCallback(
    ({ animationY, scrollToTop, isScrolled }) => {
      const { activeTab, currentCount, pastCount } = config;

      const showPlaylistsSwitcher =
        (activeTab === 'current' && pastCount !== 0) ||
        (activeTab === 'past' && currentCount !== 0);
      const onTitlePressIn = () => {
        if (!showPlaylistsSwitcher) {
          return;
        }
        openPopupByVariant(PLAYLISTS_POPUP_ID);
      };

      return (
        <Header
          activeVisibility={activeVisibility}
          animationY={animationY}
          scrollToTop={scrollToTop}
          isScrolled={isScrolled}
          onPress={onTitlePressIn}
          isPressableTitle={showPlaylistsSwitcher}
          isDirtySorting={isDirtySorting}
          isFailed={isFailed}
        />
      );
    },
    [activeVisibility, isFailed, config, isDirtySorting]
  );

  const renderBody: TRefreshableRenderer = useCallback(() => {
    const { visibility } = activeVisibility;
    const { vendor, activeTab, currentError, pastError } = config;
    const isSpotify = vendor === 'spotify';
    const isCurrentActive = activeTab === ACTIVE_TAB.current;
    const spotifyOptions = isCurrentActive
      ? SORTING_CURRENT_SPOTIFY_OPTIONS
      : SORTING_PAST_SPOTIFY_OPTIONS;
    const appleOptions = isCurrentActive
      ? SORTING_CURRENT_APPLE_OPTIONS
      : SORTING_PAST_APPLE_OPTIONS;
    const sortingOptions = isSpotify ? spotifyOptions : appleOptions;
    const activeOption = isCurrentActive
      ? current.config!.order_by
      : past.config!.order_by;
    const isIos = Platform.OS === 'ios';
    const marketCodePlaylistStreams = _.path(
      ['params', ROUTE_PARAMS.marketCodePlaylistStreams],
      route
    );
    const marketCodePlaylistOwner = _.path(
      ['params', ROUTE_PARAMS.marketCodePlaylistOwner],
      route
    );

    if (
      visibility.offline ||
      _.path('offline', currentError) ||
      _.path('offline', pastError)
    )
      return renderOffline();

    if (
      isFailed ||
      _.path('timeout', currentError) ||
      _.path('timeout', pastError)
    ) {
      return renderFailedToLoad();
    }

    return (
      <SBox position="relative" flex={1} pt={maxHeight} pb={32}>
        <SBox
          position="absolute"
          top={285}
          bottom={0}
          width={1}
          height="150%"
          bg="ebonyClay"
        />
        <SBox position="absolute" top={255}>
          <Arc />
        </SBox>

        {visibility.skeleton && !visibility.extra.search ? <Skeleton /> : null}

        {/*search fail*/}
        {visibility.error && visibility.extra.search && !visibility.offline ? (
          <ViewLoadFailed
            variant="track-playlists-search"
            verticalOffset={-72}
          />
        ) : null}

        {/*local tab fail*/}
        {visibility.error &&
        !visibility.extra.search &&
        !visibility.offline &&
        !visibility.extra.loading ? (
          <ViewLoadFailed
            variant="track-playlists-tab"
            vendor={isSpotify ? 'Spotify' : 'Apple Music'}
            activeTab={activeTab}
            verticalOffset={-88}
          />
        ) : null}

        {visibility.empty && !visibility.offline && !visibility.error ? (
          <ViewEmptySearch
            keyboardHiddenMargin={isIos ? 66 : 100}
            keyboardDisplayedMargin={isIos ? 39 : -40}
          />
        ) : null}

        {visibility.extra.search &&
        visibility.extra.loading &&
        !visibility.refresh ? (
          <LoadingOverlay variant="transparent" />
        ) : null}

        {visibility.data ? (
          <SBox position="relative" flex={1} pb={29}>
            <SortBlock
              options={sortingOptions}
              value={1}
              dateRange={DATE_RANGES.WEEK}
              variant="light"
              market={marketCodePlaylistStreams || marketCodePlaylistOwner}
              playlistVendor={vendor}
              activeOption={activeOption as string}
              activeTab={activeTab}
              hideStreams={activeTab !== ACTIVE_TAB.current}
            />
            <List />
          </SBox>
        ) : null}
        {visibility.extra.refill ? <RefillingIndicator /> : null}
      </SBox>
    );
  }, [activeVisibility, isFailed, config, past, current, route]);

  const renderBgLayer: TRefreshableRenderer = useCallback(() => {
    const { visibility } = activeVisibility;
    const { vendor, currentError, pastError } = config;
    const imageUrl = _.path('data.image_url', trackData);

    if (
      visibility.offline ||
      isFailed ||
      _.path('offline', currentError) ||
      _.path('offline', pastError) ||
      _.path('timeout', currentError) ||
      _.path('timeout', pastError)
    )
      return false;

    const gradientHeight = DEVICE_HEIGHT * 0.7;
    const gradientColors =
      vendor === 'apple'
        ? theme.gradients.listHeaderTrackApple
        : vendor === 'spotify'
        ? theme.gradients.listHeaderTrackSpotify
        : theme.gradients.cornflower2;
    const imageHeight = 375;

    return (
      <SBox height={gradientHeight}>
        {imageUrl ? (
          <SBox height={imageHeight} width={1} position="absolute">
            <SImage
              height={imageHeight}
              width={1}
              resizeMode="cover"
              source={{
                uri: imageUrl,
              }}
            />
          </SBox>
        ) : null}

        <SHeaderGradient
          height={300}
          top={200}
          colors={theme.gradients.playlistsImageCover}
          locations={[0, 0.24, 1]}
        />

        <SBox flex={1} opacity={0.95}>
          <LinearGradient
            colors={gradientColors}
            locations={[0, 0.65, 1]}
            style={{ flex: 1 }}
          />
        </SBox>
      </SBox>
    );
  }, [activeVisibility, config, trackData, isFailed]);

  const renderFgLayer = useCallback(() => {
    const { activeTab, vendor, market } = config;
    const defaultValue = _.isNil(activeTab) ? ACTIVE_TAB.current : activeTab;
    const isCurrentActive = defaultValue === ACTIVE_TAB.current;
    const spotifyOptions = isCurrentActive
      ? SORTING_CURRENT_SPOTIFY_OPTIONS
      : SORTING_PAST_SPOTIFY_OPTIONS;
    const appleOptions = isCurrentActive
      ? SORTING_CURRENT_APPLE_OPTIONS
      : SORTING_PAST_APPLE_OPTIONS;
    const isSpotify = vendor === 'spotify';
    const sortingOptions = isSpotify ? spotifyOptions : appleOptions;
    const filterConfig = isCurrentActive ? current.config : past.config;

    const params = {
      playlistOptions,
      market,
      sortingOptions,
      filterConfig,
      categoryOptions,
    };

    return (
      <>
        <Portal id={`POPUP_PLAYLISTS:${id}`} updateIfAnyChanged={params}>
          <SwipeablePopup
            fullheight
            variant={PLAYLISTS_POPUP_ID}
            content={
              <PopupSelector
                id={PLAYLISTS_POPUP_ID}
                title="Playlists"
                renderLabelExtra={({ quantity }: any) => (
                  <SBox
                    position="absolute"
                    right={54}
                    width={88}
                    top={13}
                    alignItems="flex-end"
                  >
                    <SSortingText color="richBlack">
                      {formatStreamDigit(quantity as number, {
                        addComma: true,
                      })}
                    </SSortingText>
                  </SBox>
                )}
                renderInfo={() => <PlaylistsInfo />}
                options={playlistOptions}
                value={defaultValue}
                onSubmit={activeTab => {
                  setConfig({
                    activeTab,
                  } as any);
                  getSettings(null, FETCH_TYPE.force);
                  onPlaylistsCurrentPastSelected({
                    vendor,
                    type: activeTab as ACTIVE_TAB,
                  });
                }}
              />
            }
          />
          <SwipeablePopup
            fullheight
            variant={PLAYLISTS_SORTING_POPUP_ID}
            content={
              <InfoPlaylists
                id={PLAYLISTS_SORTING_POPUP_ID}
                vendor={vendor}
                categoryOptions={categoryOptions}
                sortingOptions={sortingOptions}
                market={market}
                config={filterConfig as TFilterConfig}
                onSubmit={params => {
                  const categoryId = _.path('category_id', params);
                  if (!_.pathEq(['category_id'], categoryId)(filterConfig)) {
                    onPlaylistsFilteringApplied({
                      type: activeTab,
                      filter: _.compose(
                        _.capitalizeSafe,
                        _.path('label'),
                        _.find({ value: categoryId })
                      )(categoryOptions),
                    });
                  }
                  const sort = _.path('order_by', params);
                  if (!_.pathEq(['order_by'], sort)(filterConfig)) {
                    onPlaylistsSortingApplied({
                      type: activeTab,
                      sort: _.compose(
                        _.path('label'),
                        _.find({ value: sort })
                      )(sortingOptions),
                    });
                  }

                  getData(params, FETCH_TYPE.force);
                }}
              />
            }
          />
        </Portal>
      </>
    );
  }, [
    playlistOptions,
    setConfig,
    getData,
    getSettings,
    config,
    past,
    current,
    categoryOptions,
  ]);

  const { visibility } = activeVisibility;

  return (
    <SKeyboardAvoidingView behavior="padding" enabled>
      <RefreshableView
        testID="playlist-refreshable-view"
        loading={refreshing}
        indicatorLight
        indicatorOffsetTop={maxHeight - 15}
        onPullDown={() => {
          if (
            visibility.refresh ||
            visibility.extra.refill ||
            visibility.skeleton
          ) {
            return;
          }
          refresh();
        }}
        // infinite pagination - get next page when we don't have payload
        onScrollReachBottom={() => {
          if (visibility.refresh || visibility.extra.refill) {
            return;
          }
          getData(null, FETCH_TYPE.refill);
        }}
        renderHeader={renderHeader}
        renderBody={renderBody}
        renderBgLayer={renderBgLayer}
        renderFgLayer={renderFgLayer}
        name={ROUTES.playlists}
        withNativeDriver
        withoutBottomTabNavigator
      />
    </SKeyboardAvoidingView>
  );
});
