import React, { memo, useCallback } from 'react';
import { Dimensions, Pressable } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { Action } from 'redux-actions';
import { RefreshableView } from '../../common/components/refreshable-view';
import { theme } from '../../app/theme';
import { SBoxAnimated } from '../../common/s-components/layout/s-box-animated';
import { fp as _ } from '../../common/utils/fp';
import { SBox } from '../../common/s-components/layout/s-box';
import {
  getStatusBarHeight,
  addSafeArea,
  isBrokenIsrc,
  setDataFreshnessIndicatorVariant,
  getAnimations,
} from '../../common/transducers';
import { BackButton } from '../../common/components/back-button';
import { Tabs } from '../../common/components/tabs';
import { Router } from '../../common/utils/navigation-service';
import { Arc } from '../../common/components/arc';
import { SearchInput } from '../../common/components/search-input';
import {
  TOption,
  TVisibility,
  TFilters,
  TTabUndef,
  TGoToTrack,
  TSetFilter,
  TSelectTab,
  TTab,
  TRoute,
} from '../types';
import { SRow } from '../../common/s-components/layout/s-row';
import WithMarketIndicator from '../../common/containers/with-market-indicator';
import { DataFreshnessIndicator } from '../../common/components/data-freshness-indicator';
import {
  exitPage,
  fullChartFilterOpened,
  fullChartFilterOptionSelected,
  PAGES,
  updatePageMeta,
} from '../../analytics';
import Tab from '../containers/tab';
import { areOptionsEqual, getBgPadding, getFilterLog } from '../transducers';
import { updateTabAnalytics } from '../services';
import { SwipeablePopup } from '../../common/components/bottom-sheet/swipeable-popup';
import { Portal } from '../../common/utils/portal/portal';
import { SKeyboardAvoidingView } from '../../common/s-components/s-keyboard-avoiding-view';
import { openPopupByVariant } from '../../common/utils/keyboard-service';
import { SText } from '../../common/s-components/typography/s-text';
import {
  TMarketUndef,
  TRefreshableRenderer,
  TTrackWithStream,
} from '../../common/types';
import { POPUP_FILTER_ID } from '../constants';
import { MarketInfo } from '../../common/components/market-info';
import { ROUTE_PARAMS, ROUTES } from '../../app/constants';
import { TToggleStarred } from '../../common/submodules/starring-tracks/types';
import { Icon } from '../../common/components/icon';
import { Flag } from '../../common/components/flag';
import { SPageTitle } from '../s-components/s-page-title';
import { SPageTitleSmall } from '../s-components/s-page-title-small';
import { PopupFilter } from './popup-filter';

const HEADER_HEIGHT = addSafeArea(123);
const HEADER_WITHOUT_SEARCH = addSafeArea(88);
const maxHeight = HEADER_HEIGHT;
const minHeight = addSafeArea(82);
const safeArea = getStatusBarHeight();
const heightDiff = maxHeight - minHeight;
const headerAdditionalValue = 60;
// const scrollTop = headerAdditionalValue + 10;
const { height } = Dimensions.get('window');

export type TProps = {
  route: TRoute;
  items?: TTrackWithStream[];
  refreshing: boolean;
  refresh: () => void;
  visibility: TVisibility;
  activeTab?: TTabUndef;
  toggleStarred: TToggleStarred;
  filters: TFilters;
  setFilter: TSetFilter;
  ownersOptions: TOption[];
  filterTitle?: string;
  date?: string;
  market: TMarketUndef;
  homeMarket: TMarketUndef;
  selectTab: TSelectTab;
};

const Animation = getAnimations({
  headerBg: {
    opacity: {
      inputRange: [0, heightDiff],
      outputRange: [0, 1],
    },
    translateY: {
      inputRange: [0, heightDiff],
      outputRange: [0, -heightDiff],
    },
  },

  title: {
    opacity: {
      inputRange: [0, heightDiff / 2, heightDiff / 1.5, heightDiff],
      outputRange: [1, 1, 0, 0],
    },
    translateY: {
      inputRange: [0, heightDiff / 1.5, heightDiff / 1.5, heightDiff],
      outputRange: [safeArea + 21, safeArea + 12, safeArea - 80, safeArea - 80],
    },
  },

  titleSmall: {
    opacity: {
      inputRange: [0, heightDiff / 2, heightDiff / 1.5, heightDiff],
      outputRange: [0, 0, 1, 1],
    },
    translateY: {
      inputRange: [0, heightDiff / 3, heightDiff / 2, heightDiff],
      outputRange: [safeArea - 50, safeArea + 65, safeArea + 20, safeArea + 3],
    },
    scaleY: {
      inputRange: [0, heightDiff / 3, heightDiff / 2],
      outputRange: [0, 1, 1],
    },
  },

  arrow: {
    translateY: {
      inputRange: [0, heightDiff],
      outputRange: [safeArea + 12, safeArea],
    },
  },

  clock: {
    translateY: {
      inputRange: [0, heightDiff],
      outputRange: [safeArea + 12, safeArea],
    },
  },

  tabs: {
    translateY: {
      inputRange: [0, heightDiff],
      outputRange: [safeArea + 101, safeArea + 59],
    },
  },

  searchBox: {
    translateY: {
      inputRange: [0, heightDiff / 1.5, heightDiff / 1.5, heightDiff],
      outputRange: [safeArea + 156, safeArea + 144, safeArea + 144, -44],
    },
    opacity: {
      inputRange: [0, heightDiff / 1.5, heightDiff / 1.5, heightDiff],
      outputRange: [1, 1, 0, 0],
    },
  },
  input: {
    translateY: 0,
    scaleY: {
      inputRange: [0, heightDiff / 1.5, heightDiff],
      outputRange: [1, 0, 0],
    },
  },
});

export const Charts: React.FC<TProps> = memo(props => {
  const {
    refreshing,
    refresh,
    visibility,
    activeTab,
    selectTab,
    filterTitle,
    ownersOptions,
    filters,
    setFilter,
    date,
    route,
  } = props;
  const indicatorOffsetTop = visibility.errorOffline
    ? maxHeight
    : maxHeight + 80;

  const goBack = () => {
    Router.goBack();
    exitPage(PAGES.Chartstab.page);
    exitPage(PAGES.Charts.page);
  };

  const goToTrack: TGoToTrack = params => {
    if (_.isEmpty(params.trackId) || isBrokenIsrc(params.isrc)) {
      Router.goTo(ROUTES.emptytrack);
    } else {
      Router.goTo(ROUTES.track, params);
      updatePageMeta({
        page: ROUTES.track,
        track_id: params.trackId,
        track_name: params.name,
        track_artist: params.artist,
        is_starred: params.starred,
        distributor: params.distributor,
      });
    }
  };

  const logFilterSelection = (selectedOptions: Action<TFilters>) => {
    const { filters } = props;
    const lastOptions = _.path('owner', filters);
    const currentOptions = _.path('payload.owner', selectedOptions);

    if (areOptionsEqual(lastOptions, currentOptions)) return false;

    fullChartFilterOptionSelected(getFilterLog(selectedOptions));
  };

  const renderHeader: TRefreshableRenderer = useCallback(
    ({ animationY, scrollToTop, isScrolled }) => {
      const variant = setDataFreshnessIndicatorVariant('charts:info-inner', {
        empty: !(date && visibility.hasTracks),
      });

      const onTitlePressIn = () => {
        const { loading, errorOffline } = visibility;

        if (!isScrolled && !loading && !errorOffline) {
          openPopupByVariant(POPUP_FILTER_ID);
          fullChartFilterOpened();
        }
        if (isScrolled) {
          scrollToTop();
        }
      };

      const marketCode = _.path(['params', ROUTE_PARAMS.homeMarket], route);
      const pageTitle = 'Charts';

      return (
        <>
          <SBoxAnimated
            style={Animation.headerBg(animationY)}
            height={maxHeight}
            bg={theme.colors.vulcan}
            position="absolute"
            width={1}
          />

          <SBoxAnimated
            style={Animation.titleSmall(animationY)}
            position="absolute"
            alignItems="center"
            width={1}
          >
            <Pressable
              onPress={onTitlePressIn}
              testID="charts-tappable-title"
              hitSlop={{ top: 10, bottom: 10 }}
            >
              {({ pressed }) => (
                <SRow
                  alignItems="center"
                  opacity={pressed ? 0.7 : 1}
                  pl={4}
                  py={10}
                >
                  <Flag
                    market={marketCode}
                    width={16}
                    height={16}
                    marginTop={2}
                    variant="light"
                  />
                  <SPageTitleSmall ml={11}>{pageTitle}</SPageTitleSmall>
                </SRow>
              )}
            </Pressable>
          </SBoxAnimated>

          <SBoxAnimated
            style={Animation.title(animationY)}
            position="absolute"
            width={1}
          >
            <SBox alignItems="center">
              <Pressable
                onPress={onTitlePressIn}
                testID="charts-tappable-title"
                hitSlop={{ top: 20, bottom: 10, left: 20, right: 20 }}
              >
                {({ pressed }) => (
                  <>
                    <WithMarketIndicator
                      variant="market-charts"
                      notClickable
                      marketCode={marketCode}
                      pressed={pressed}
                    >
                      <SRow>
                        <SPageTitle numberOfLines={1}>{pageTitle}</SPageTitle>
                        {!visibility.errorOffline ? (
                          <Icon
                            name="down-ind"
                            size={12}
                            color="white"
                            pl={7}
                            pt={7}
                          />
                        ) : null}
                      </SRow>
                    </WithMarketIndicator>
                    <SRow
                      pt={7}
                      justifyContent="center"
                      opacity={pressed ? 0.7 : 1}
                    >
                      {!visibility.errorOffline ? (
                        <SText sm medium>
                          {filterTitle}
                        </SText>
                      ) : null}
                    </SRow>
                  </>
                )}
              </Pressable>
            </SBox>
          </SBoxAnimated>

          {!visibility.noDate ? (
            <SBoxAnimated
              style={[Animation.clock(animationY)]}
              position="absolute"
              right={16}
            >
              <DataFreshnessIndicator
                date={date!}
                vendor={activeTab!}
                variant={variant}
                visibleTopCharts={visibility.items}
              />
            </SBoxAnimated>
          ) : null}

          {!visibility.errorOffline ? (
            <SBoxAnimated
              style={Animation.tabs(animationY)}
              position="absolute"
              width={1}
            >
              <Tabs
                // testID="charts-tabs"
                light={!isScrolled}
                active={activeTab}
                tabs={[
                  { id: 'spotify', name: 'spotify' },
                  { id: 'apple', name: 'apple music' },
                ]}
                onSelect={(tab: string) => {
                  if (isScrolled) {
                    scrollToTop(true);
                  }
                  selectTab(tab as TTab);
                  updateTabAnalytics(tab as TTab);
                }}
              />
            </SBoxAnimated>
          ) : null}

          {visibility.searchInput ? (
            <SBoxAnimated
              style={[Animation.searchBox(animationY)]}
              width={1}
              position="absolute"
            >
              <SBoxAnimated style={[Animation.input(animationY)]} mx={16}>
                <SearchInput
                  value={filters.search}
                  placeholder="Find in chart"
                  onChange={(search: string) => {
                    setFilter({ search });
                    setTimeout(() => {
                      scrollToTop(true);
                    }, 100);
                  }}
                />
              </SBoxAnimated>
            </SBoxAnimated>
          ) : null}

          <SBoxAnimated
            style={[Animation.arrow(animationY)]}
            position="absolute"
            left={16}
          >
            <BackButton testID="charts-back-button" onPress={goBack} fixed />
          </SBoxAnimated>
        </>
      );
    },
    [
      activeTab,
      selectTab,
      filterTitle,
      visibility,
      filters,
      setFilter,
      date,
      route,
    ]
  );

  const renderBody = useCallback(() => {
    const maxHeight = visibility.errorOffline
      ? 0
      : visibility.searchInput
      ? HEADER_HEIGHT
      : HEADER_WITHOUT_SEARCH;

    const bgPadding = getBgPadding(visibility);
    const arcTop =
      visibility.errorCharts || visibility.noTracks || visibility.noAvailable
        ? -6
        : 27;

    return (
      <>
        <SBox position="relative" flex={1} mt={maxHeight + 93}>
          <SBox
            position="absolute"
            top={bgPadding}
            bottom={0}
            width={1}
            height="150%"
            bg="ebonyClay"
          />
          <SBox position="absolute" top={arcTop}>
            <Arc fill="ebonyClay" />
          </SBox>

          <Tab
            {...props}
            goToTrack={goToTrack}
            minHeight={minHeight}
            headerAdditionalValue={headerAdditionalValue}
          />
        </SBox>
      </>
    );
  }, [visibility]);

  const renderBgLayer = useCallback(() => {
    const gradientColors =
      activeTab === 'apple'
        ? theme.gradients.topChartsApple
        : theme.gradients.topChartsSpotify;
    return visibility.errorOffline ? null : (
      <SBox flex={1} pb={height / 3}>
        <LinearGradient
          colors={gradientColors}
          style={{ flex: 1 }}
          locations={[0, 1]}
        />
      </SBox>
    );
  }, [visibility, activeTab]);

  const renderFgLayer = useCallback(() => {
    const marketCode = _.path(['params', ROUTE_PARAMS.homeMarket], route);

    const params = {
      ownersOptions,
      filters,
      marketCode,
    };

    return (
      <>
        <Portal id="POPUP_FILTER_ID" updateIfAnyChanged={params}>
          <SwipeablePopup
            variant={POPUP_FILTER_ID}
            fullheight
            content={
              <PopupFilter
                id={POPUP_FILTER_ID}
                title="Filtering"
                optionsTitle="Track Owner"
                renderInfo={() => <MarketInfo marketCode={marketCode} />}
                value={_.path('owner', filters)}
                onSubmit={_.compose(
                  _.tap((value: Action<TFilters>) => {
                    logFilterSelection(value);
                  }),
                  setFilter,
                  _.objOf('owner')
                )}
              />
            }
          />
        </Portal>
      </>
    );
  }, [ownersOptions, filters, setFilter, route]);

  return (
    <SKeyboardAvoidingView behavior="padding" enabled>
      <RefreshableView
        testID="charts-refreshable-view"
        indicatorLight
        loading={refreshing}
        indicatorOffsetTop={indicatorOffsetTop}
        onPullDown={refresh}
        renderHeader={renderHeader}
        renderBody={renderBody}
        renderBgLayer={renderBgLayer}
        renderFgLayer={renderFgLayer}
        withoutBottomTabNavigator
        name={ROUTES.charts}
        withNativeDriver
        // scrollTop={scrollTop}
      />
    </SKeyboardAvoidingView>
  );
});
