import React, { memo, useCallback } from 'react';
import { Dimensions, Platform } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { RefreshableView } from '../../common/components/refreshable-view';
import { FETCH_TYPE } from '../../common/constants';
import { SBox } from '../../common/s-components/layout/s-box';
import { CardsOpened } from './cards-opened';
import { SKeyboardAvoidingView } from '../../common/s-components/s-keyboard-avoiding-view';
import { ViewNetworkFailed } from '../../common/components/view-network-failed';
import { ViewNoNotificationResult } from './view-no-notification-result';
import { Skeleton } from './skeleton';
import { ViewNoStarred } from '../../common/components/view-no-starred';
import { ViewNotificationPermission } from './view-notification-permission';
import { fp as _ } from '../../common/utils/fp';
import { addSafeArea } from '../../common/transducers';
import {
  notificationOpenedFromPage,
  notificationsFilterOptionsSelected,
  PAGES,
  updatePageMeta,
} from '../../analytics';
import { RefillingIndicator } from '../../common/components/refilling-indicator';
import { ViewLoadFailed } from '../../common/components/view-load-failed';
import { ROUTE_PARAMS, ROUTES } from '../../app/constants';
import { Router } from '../../common/utils/navigation-service';
import {
  TGoToCharts,
  TGoToPlaylist,
  TGoToTrack,
  TState as TNotificationsState,
  TVisibility,
} from '../types';
import {
  NEntityInfinite,
  NOTIFICATION_TOPIC,
  TRefreshableRenderer,
} from '../../common/types';
import { NotificationSettings } from './notification-settings';
import { ViewNoNotificationResultWithNotificationSettings } from './view-no-notification-result-with-notification-settings';
import { TState as TNotificationSettingsState } from '../../notification-settings/types';
import { Portal } from '../../common/utils/portal/portal';
import { SwipeablePopup } from '../../common/components/bottom-sheet/swipeable-popup';
import { InfoNotifications } from './info-notifications';
import { Header } from './header';
import {
  logNotificationOpenedChartPage,
  logNotificationOpenedChartTrack,
  logNotificationOpenedPlaylist,
} from '../services/analytics';
import { EPlaylistSourcePage } from '../../analytics/types';
import { theme } from '../../app/theme';
import { Arc } from '../../common/components/arc';
import {
  NOTIFICATIONS_FILTER_ID,
  NOTIFICATIONS_INFO_ID,
  PORTAL_ID,
} from '../constants';
import { PopupFilter } from './filters/popup-filter';
import { Info } from './filters/info';
import TEntityConfig = NEntityInfinite.TEntityConfig;
import { ViewEmptySearch } from './view-empty-search';
import { getFiltersLog } from '../transducers';

const HEADER_HEIGHT = addSafeArea(205);
const HEADER_WITHOUT_SEARCH = addSafeArea(122);
const { height: screenHeight } = Dimensions.get('window');
const isIOS = Platform.OS === 'ios';

type TProps = {
  refreshing: boolean;
  visibility: TVisibility;
  getData: (type: FETCH_TYPE) => void;
  refresh: () => void;
  notificationSettings: TNotificationSettingsState['notificationSettings'];
  notificationSettingsKeySelector: boolean;
  notifications: TNotificationsState['notifications'];
  setConfig: (config: TEntityConfig) => void;
};

export const Notifications: React.FC<TProps> = memo(props => {
  const {
    refreshing,
    refresh,
    getData,
    visibility,
    notificationSettings,
    notifications,
    setConfig,
  } = props;

  const isSmallHeader = _.path('showSmallHeader', visibility);
  const maxHeight = isSmallHeader ? HEADER_WITHOUT_SEARCH : HEADER_HEIGHT;

  const goToTrack: TGoToTrack = params => {
    Router.goTo(ROUTES.track, params);
    notificationOpenedFromPage();
    logNotificationOpenedChartTrack(params);
    logNotificationOpenedPlaylist(params);
    updatePageMeta({
      page: PAGES.Track.page,
      track_id: params.trackId,
      track_name: params.name,
      track_artist: params.artist,
      is_starred: undefined,
      isrc: params.isrc,
    });
  };
  const goToPlaylist: TGoToPlaylist = params => {
    const marketCode =
      params.vendor === 'apple'
        ? params.country_code !== '_gl' && params.country_code !== 'global'
          ? params.country_code
          : 'us'
        : undefined;

    Router.goTo(ROUTES.playlist, {
      [ROUTE_PARAMS.playlistrootId]: params.playlist_id,
      [ROUTE_PARAMS.playlistrootMarket]: marketCode,
      [ROUTE_PARAMS.playlistrootVendor]: params.vendor,
      playlistName: params.playlist_name,
    });
    notificationOpenedFromPage();
    logNotificationOpenedChartTrack(params);
    logNotificationOpenedPlaylist(params);

    updatePageMeta({
      page: PAGES.Playlist.page,
      source_page: EPlaylistSourcePage.notifications,
      playlist_id: params.playlist_id,
      playlist_vendor: _.capitalizeSafe(params.vendor),
    });
  };
  const goToCharts: TGoToCharts = params => {
    Router.goTo(ROUTES.charts, {
      cvendor: params.vendor,
      homeMarket: params.country_code,
      homeVendor: params.vendor,
    });
    notificationOpenedFromPage();
    logNotificationOpenedChartPage(params);
  };
  const goTo: TGoToTrack = params => {
    if (params.topic === NOTIFICATION_TOPIC.ChartUpdate) {
      goToCharts(params);
    } else if (_.includes('playlist', params.topic)) {
      goToPlaylist(params);
    } else {
      goToTrack(params);
    }
  };

  const logFilterSelection = (
    selectedOptions: NEntityInfinite.TEntityConfig
  ) => {
    const config = _.path('config', notifications)!;
    if (_.isEqual(config, selectedOptions)) return;

    notificationsFilterOptionsSelected(getFiltersLog(selectedOptions));
  };

  const renderFgLayer = () => {
    const config = _.path('config', notifications)!;
    return (
      <Portal id={PORTAL_ID} updateIfAnyChanged={{ config }}>
        <SwipeablePopup
          variant={NOTIFICATIONS_INFO_ID}
          content={<InfoNotifications />}
        />
        <SwipeablePopup
          variant={NOTIFICATIONS_FILTER_ID}
          fullheight
          content={
            <PopupFilter
              id={NOTIFICATIONS_FILTER_ID}
              title="Filtering"
              renderInfo={() => <Info />}
              config={config}
              onSubmit={config => {
                setConfig(config);
                logFilterSelection(config);
                getData(FETCH_TYPE.filter);
              }}
            />
          }
        />
      </Portal>
    );
  };

  const renderBgLayer = useCallback(() => {
    const gradientColors = theme.gradients.yellowToOrange;
    return (
      <SBox flex={1} pb={screenHeight / 2.6}>
        <LinearGradient
          colors={gradientColors}
          style={{ flex: 1 }}
          locations={isSmallHeader ? [0, 0.35, 1] : [0, 0.55, 1]}
        />
      </SBox>
    );
  }, []);

  const renderHeader: TRefreshableRenderer = ({
    animationY,
    scrollToTop,
    isScrolled,
  }) => {
    return (
      <Header
        animationY={animationY}
        scrollToTop={scrollToTop}
        isScrolled={isScrolled}
      />
    );
  };

  const renderBody = useCallback(() => {
    const topBgOffset = isSmallHeader ? 140 : 240;
    const topArcOffset = isSmallHeader ? 110 : 210;

    return (
      <>
        <SBox width={1} position="relative" flex={1} pt={maxHeight - 51}>
          <SBox
            position="absolute"
            top={topBgOffset}
            width={1}
            height="150%"
            bg="ebonyClay"
          />
          <SBox position="absolute" top={topArcOffset}>
            <Arc fill="ebonyClay" />
          </SBox>

          {visibility.skeleton ? <Skeleton /> : null}

          {visibility.noStarred ? (
            <ViewNoStarred verticalOffset={-33} variant="notifications" />
          ) : null}

          {visibility.failedToLoadNotifications ? (
            <ViewLoadFailed variant="notifications" verticalOffset={-25} />
          ) : null}

          {visibility.noNotificationsYet ? (
            <ViewNoNotificationResult verticalOffset={-21} />
          ) : null}

          {visibility.noNotificationsAndDisabled ? (
            <ViewNoNotificationResultWithNotificationSettings
              verticalOffset={isIOS ? -136 : 100}
            />
          ) : null}

          {visibility.offline ? (
            <ViewNetworkFailed verticalOffset={-21} />
          ) : null}

          {visibility.failedSearchNotifications ? (
            <ViewLoadFailed
              variant="notifications-search"
              verticalOffset={-24}
            />
          ) : null}

          {visibility.noSearchResults ? (
            <ViewEmptySearch
              keyboardHiddenMargin={32}
              keyboardDisplayedMargin={isIOS ? -8 : 0}
            />
          ) : null}

          {visibility.showPermission ? <ViewNotificationPermission /> : null}

          {visibility.showNotificationSettings &&
            !notificationSettings.error && <NotificationSettings />}

          <SBox px={16} pt={2}>
            {visibility.data ? (
              <>
                <CardsOpened
                  cards={notifications.data!}
                  onCardPress={goTo}
                  error={
                    visibility.error &&
                    `Failed to load\nthe opened notifications.`
                  }
                />
                {visibility.extra.refill ? <RefillingIndicator /> : null}
              </>
            ) : null}
          </SBox>
        </SBox>
      </>
    );
  }, [notificationSettings, visibility, notifications]);

  const behavior =
    isIOS ||
    (!isIOS &&
      (visibility.empty || visibility.extra.search || visibility.offline))
      ? 'padding'
      : undefined;

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