import React, { useContext, useState, memo } from 'react';
import { TouchableWithoutFeedback, Keyboard, Animated } from 'react-native';
// @ts-ignore
import GSwipeable from 'react-native-gesture-handler/Swipeable';
import { LinearGradient } from 'expo-linear-gradient';
import { SText } from '../s-components/typography/s-text';
import { SBox } from '../s-components/layout/s-box';
import { SRow } from '../s-components/layout/s-row';
import { PositionTrendsLabel } from './position-trends-label';
import { SSwipeableIcon } from '../s-components/s-swipeable-icon';
import { SBoxAnimated } from '../s-components/layout/s-box-animated';
import { SRectButton } from '../s-components/s-rect-button';
import { fp as _ } from '../utils/fp';
import { SH5 } from '../s-components/typography/s-h5';
import { StarredIcon } from './starred-icon';
import { theme } from '../../app/theme';
import { blurSubject$ } from '../utils/input-service';
import { SH6 } from '../s-components/typography/s-h6';
import { BlueDot } from './blue-dot';
import { SkeletonString } from './skeleton-string';
import {
  EDistributor,
  TRACK_CARD_HEIGHT,
  TRACK_LIST_CARD_AVATAR_HEIGHT,
  TRACK_LIST_CARD_HEIGHT,
} from '../constants';
import { SDotGrey } from '../s-components/s-dot-grey';
import {
  formatStreamDigit,
  formatYearDate,
  getRangeWidth,
} from '../transducers';
import {
  TPageVariant,
  TPositionTrend,
  TTimerange,
  TTrackId,
  TTrackParams,
} from '../types';
import { SSwipeableHighlightLine } from '../s-components/s-swipeable-highlight-line';
import { StreamInfoContainer } from './stream-info-container';
import { SBlueDot } from '../s-components/s-blue-dot';
import { SSwipeableHighlightContainer } from '../s-components/s-swipeable-highlight-container';
import { ContextStarred } from '../context';
import { toasterSubject$ } from '../submodules/toaster/services/toaster-service';
import { Image } from './image';

import { EToastTemplate } from '../submodules/toaster/types';
import { PositionTrends } from './position-trends';
import { DistributorIcon } from './distributor-icon';
import { SSwipeableRow } from '../s-components/s-swipeable-row';
import { SSwipeableImageBox } from '../s-components/s-swipeable-image-box';
import { SSwipeableSmallImageBox } from '../s-components/s-swipeable-small-image-box';
import { SSwipeableContent } from '../s-components/s-swipeable-content';
import { SSwipeableName } from '../s-components/s-swipeable-name';
import { SStreamContainer } from '../s-components/s-stream-container';
import { NON_SONY } from '../../analytics/constants';

type TProps = {
  id?: TTrackId | null;
  isrc: string;
  name: string;
  image_url: string;
  artist: string;
  artists?: string;
  streamInfo?: string;
  vendor: 'apple' | 'spotify';
  onRightOpen?: (value: string) => void;
  onRightClose?: (value: string) => void;
  onSwipeableRightWillOpen?: (value: string) => void;
  onPress?: (params: TTrackParams) => void;
  onPressRight?: (params: TTrackParams) => void;
  change?: number;
  position?: number;
  showStarred?: boolean;
  showPosition?: boolean;
  showChange?: boolean;
  showBlueDot?: boolean;
  showStreamCount?: boolean;
  showStreamInfo?: boolean;
  streamRange?: TTimerange | null;
  starred?: boolean;
  variant?: string;
  isNew?: boolean;
  available?: boolean;
  marketName?: string;
  forwardedRef: any;
  optimistic?: boolean;
  cardHeight: number;
  highlightedIsrc: string;
  trend?: number;
  streams?: string;
  added_date?: string;
  current_position?: number;
  streamsTrend?: TPositionTrend;
  keyComposed: string;
  starSource: string;
  disabled: boolean;
  distributed_by: EDistributor;
  pageVariant: TPageVariant;
};

const SwipeableComponent: React.FC<TProps> = memo((props: TProps) => {
  const [pressed, setPressed] = useState(false);
  const [pressedBtn, setBtnPressed] = useState(false);
  const { error, offline } = useContext(ContextStarred);

  const renderRightActions = (
    progress: Animated.AnimatedInterpolation<any>
  ) => {
    const {
      starred,
      onPressRight,
      id,
      isrc,
      variant,
      vendor,
      showStreamInfo,
      ...rest
    } = props;
    const trans = progress.interpolate({
      inputRange: [0, 1],
      outputRange: [72, 0],
    });

    const iconColor =
      starred && variant === 'dark'
        ? theme.colors.wildStrawberry
        : theme.colors.white;

    const cardSize = showStreamInfo
      ? TRACK_LIST_CARD_HEIGHT
      : TRACK_CARD_HEIGHT;

    return (
      <SRow
        width={72}
        style={{ borderTopRightRadius: 8, borderBottomRightRadius: 8 }}
      >
        <SBoxAnimated style={{ transform: [{ translateX: trans }] }}>
          <TouchableWithoutFeedback
            testID="swipeable-star"
            onPress={() => {
              if (_.isNotNil(rest.optimistic)) return;
              const data = _.omit([
                'onPress',
                'onSwipeableRightWillOpen',
                'forwardedRef',
                'onRightOpen',
                'onRightClose',
              ])(rest) as TTrackParams;
              if (error || offline) {
                toasterSubject$.next({
                  template: EToastTemplate.starLoadError,
                });
                return;
              }
              onPressRight!({ ...data, isrc, trackId: id!, vendor });
            }}
            onPressIn={() => {
              setBtnPressed(true);
            }}
            onPressOut={() => {
              setBtnPressed(false);
            }}
          >
            <SRectButton height={cardSize} variant={variant} /*height: ${80};*/>
              <SSwipeableIcon
                name={starred ? 'star' : 'star-outlined'}
                size={31}
                color={iconColor}
                opacity={pressedBtn ? 0.7 : 1}
              />
            </SRectButton>
          </TouchableWithoutFeedback>
        </SBoxAnimated>
      </SRow>
    );
  };

  const {
    id,
    name,
    artist,
    artists,
    streamInfo,
    onRightOpen,
    onRightClose,
    onPress,
    forwardedRef,
    image_url,
    isNew,
    showStarred,
    showPosition,
    showChange,
    showStreamCount,
    showBlueDot,
    streamRange,
    starred,
    position,
    change,
    onSwipeableRightWillOpen,
    variant,
    vendor,
    available,
    marketName,
    isrc,
    cardHeight,
    showStreamInfo,
    highlightedIsrc,
    trend,
    streams,
    added_date,
    current_position,
    streamsTrend,
    keyComposed,
    distributed_by,
    pageVariant,
  } = props;

  const itemBg =
    variant === 'dark' ? theme.colors.fiord : theme.colorsRgba.item;
  const itemPressedBg =
    variant === 'dark'
      ? theme.colors.pickledBluewood
      : theme.colorsRgba.itemPressed;
  const swipeableBoxBg = pressed ? itemPressedBg : itemBg;

  const SSwipeableImageContainer = showStreamInfo
    ? SSwipeableSmallImageBox
    : SSwipeableImageBox;
  const pictureHolder =
    variant === 'dark'
      ? theme.gradients.pictureHolderDark
      : theme.gradients.pictureHolderLight;

  // ByGenderCard difference for stream and no-stream counts
  const cardSize = showStreamInfo ? TRACK_LIST_CARD_HEIGHT : TRACK_CARD_HEIGHT;
  const pictureSize = showStreamInfo
    ? TRACK_LIST_CARD_AVATAR_HEIGHT
    : TRACK_CARD_HEIGHT;
  const widthOfRange = getRangeWidth(streamInfo!);

  const gradientColors =
    {
      amazon: theme.gradients.topChartsAmazon,
      apple: theme.gradients.topChartsApple,
      spotify: theme.gradients.topChartsSpotify,
    }[vendor] || [];

  const highlightLeft = isrc === highlightedIsrc;
  const showStarredIcon = showStarred && starred;
  const isStarredPage = pageVariant === 'starred';
  // const isChartsPage = pageVariant === 'charts';
  const isHomePage = pageVariant === 'home';
  // const isEntriesPage = pageVariant === 'home-list-2';
  const isExitsPage = pageVariant === 'home-list-4';
  const isSearchPage = pageVariant === 'search';
  const isPlacementPage = _.includes('playlist-placement')(pageVariant);

  let contentTitleMt = 2;
  if (isExitsPage) contentTitleMt = 16;
  if (isPlacementPage) contentTitleMt = 6;
  if (isSearchPage) contentTitleMt = 16;

  const renderTitle = () => {
    if (isStarredPage) {
      return (
        <SBox mt={contentTitleMt}>
          <SSwipeableName numberOfLines={1} testID="swipeable-name">
            {_.isEmpty(name) ? 'N/A' : name}
          </SSwipeableName>
          <SText numberOfLines={1} testID="swipeable-artist">
            {_.isEmpty(artists) && _.isEmpty(artist)
              ? 'N/A'
              : artists || artist}
          </SText>
        </SBox>
      );
    }

    if (isHomePage) {
      return (
        <SBox mt={contentTitleMt} pr={showStarredIcon ? 25 : 0}>
          <SSwipeableName numberOfLines={1} testID="swipeable-name">
            {_.isEmpty(name) ? 'N/A' : name}
          </SSwipeableName>
          <SText numberOfLines={1} testID="swipeable-artist">
            {_.isEmpty(artists) && _.isEmpty(artist)
              ? 'N/A'
              : artists || artist}
          </SText>
        </SBox>
      );
    }

    return (
      <SBox mt={contentTitleMt} pr={showStarredIcon ? 25 : 0}>
        <SSwipeableName numberOfLines={1} testID="swipeable-name">
          {_.isEmpty(name) ? 'N/A' : name}
        </SSwipeableName>
        <SText
          numberOfLines={1}
          pr={showStarredIcon ? 35 : 60}
          testID="swipeable-artist"
        >
          {_.isEmpty(artists) && _.isEmpty(artist) ? 'N/A' : artists || artist}
        </SText>
      </SBox>
    );
  };

  const renderPosition = () => {
    return (
      <SRow>
        {showPosition ? (
          <SH5
            color="periwinkleGray"
            testID="swipeable-position"
          >{`#${position}`}</SH5>
        ) : null}

        {isNew && showBlueDot && !showStreamInfo ? (
          <SBox ml={4.5}>
            <BlueDot />
          </SBox>
        ) : showChange ? (
          <SBox ml={4.5}>
            <PositionTrendsLabel trend={{ value: change! }} />
          </SBox>
        ) : null}
      </SRow>
    );
  };

  const renderStreamRange = () => {
    if (!!streamRange && streamInfo) {
      return (
        <>
          <SDotGrey />
          <SBox width={widthOfRange}>
            <SH6 color="periwinkleGray" numberOfLines={1}>
              {formatYearDate(streamRange.startDate)}–
              {formatYearDate(streamRange.endDate)}
            </SH6>
          </SBox>
        </>
      );
    }

    return null;
  };

  const renderStreamCount = () => {
    if (available && isStarredPage) {
      return (
        <>
          {showStreamCount && streamInfo === '' ? <SkeletonString /> : null}
          {showStreamCount && streamInfo !== '' ? (
            <SRow flexWrap="nowrap" flex={1}>
              <SH6 color="periwinkleGray" textAlign="left">
                {streamInfo === null ? 'N/A' : streamInfo}
              </SH6>
              {renderStreamRange()}
            </SRow>
          ) : null}
        </>
      );
    }

    if (available) {
      return (
        <>
          {showStreamCount && streamInfo === '' ? <SkeletonString /> : null}
          {showStreamCount && streamInfo !== '' ? (
            <SBox flex={1} alignItems="flex-end">
              <SH6 color="periwinkleGray">
                {streamInfo === null ? 'N/A' : streamInfo}
              </SH6>
            </SBox>
          ) : null}
        </>
      );
    }

    return (
      <SH6 color="periwinkleGray" numberOfLines={1} ellipsizeMode="tail">
        data unavailable in {marketName}
      </SH6>
    );
  };

  const renderStreams = () => {
    if (isSearchPage || isExitsPage || isPlacementPage) return null;

    return (
      <SStreamContainer>
        {renderPosition()}
        {renderStreamCount()}
      </SStreamContainer>
    );
  };

  return (
    <SBox height={cardHeight} pt={16} position="relative">
      <GSwipeable
        onSwipeableRightWillOpen={() => {
          onSwipeableRightWillOpen!(keyComposed);
        }}
        onSwipeableRightOpen={() => {
          if (onRightOpen) {
            onRightOpen(keyComposed);
          }
          Keyboard.dismiss();
          blurSubject$.next();
        }}
        onSwipeableWillClose={() => {
          // this.setState({ swiped: false });
        }}
        onSwipeableClose={() => {
          if (onRightClose) {
            onRightClose(keyComposed);
          }
        }}
        containerStyle={{
          borderTopRightRadius: 8,
          borderBottomRightRadius: 8,
        }}
        ref={forwardedRef}
        friction={1}
        rightThreshold={5}
        renderRightActions={renderRightActions}
        overshootRight={false}
      >
        <TouchableWithoutFeedback
          onPress={() => {
            onPress!({
              trackId: id!,
              vendor,
              name,
              artist: artists || artist,
              starred: starred!,
              available,
              isrc,
              distributor: distributed_by || NON_SONY,
            });
          }}
          onPressIn={() => {
            setPressed(true);
          }}
          onPressOut={() => {
            setPressed(false);
          }}
        >
          <SSwipeableRow height={cardSize} bg={swipeableBoxBg}>
            <SSwipeableImageContainer height={pictureSize} width={pictureSize}>
              <Image
                height={pictureSize}
                width={pictureSize}
                imageUrl={image_url}
                bgColors={pictureHolder}
              />
              {distributed_by ? (
                <SBox position="absolute" bottom={0}>
                  <DistributorIcon variant={distributed_by} />
                </SBox>
              ) : null}
            </SSwipeableImageContainer>

            <SSwipeableContent height={TRACK_CARD_HEIGHT}>
              {renderTitle()}
              <SRow>
                {showStreamInfo ? (
                  <SRow mt={7}>
                    <SText
                      fontSize={14}
                      letterSpacing={1}
                      testID="swipeable-position"
                    >
                      #
                      {formatStreamDigit(current_position, {
                        addComma: true,
                      })}
                    </SText>

                    {isNew && showBlueDot ? (
                      <SBlueDot ml={6} mt={5} testID="blue-dot-streams" />
                    ) : (
                      <PositionTrends
                        trend={{
                          value: trend!,
                          valueFormatted: formatStreamDigit(trend!),
                        }}
                        mt={1}
                        ml={4}
                      />
                    )}
                  </SRow>
                ) : null}

                {renderStreams()}
              </SRow>
            </SSwipeableContent>

            {showStreamInfo && streamsTrend ? (
              <StreamInfoContainer
                pressed={pressed}
                trend={streamsTrend}
                streams={streams}
                addedDate={added_date}
                isReversed
              />
            ) : null}

            {highlightLeft ? (
              <SSwipeableHighlightContainer>
                <SSwipeableHighlightLine>
                  <LinearGradient colors={gradientColors} style={{ flex: 1 }} />
                </SSwipeableHighlightLine>
              </SSwipeableHighlightContainer>
            ) : null}

            {showStarredIcon ? <StarredIcon /> : null}
          </SSwipeableRow>
        </TouchableWithoutFeedback>
      </GSwipeable>
    </SBox>
  );
});

SwipeableComponent.displayName = 'SwipeableComponent';
SwipeableComponent.defaultProps = {
  id: null,
  artists: '',
  streamInfo: '',
  onRightOpen: _.noop,
  onRightClose: _.noop,
  onSwipeableRightWillOpen: _.noop,
  onPress: _.noop,
  onPressRight: _.noop,
  showStarred: false,
  showPosition: false,
  showChange: false,
  showBlueDot: true,
  showStreamCount: false,
  streamRange: null,
  starred: false,
  variant: 'dark',
  isNew: false,
  available: true,
};

function forwardRef(props: any, ref: any) {
  return <SwipeableComponent {...props} forwardedRef={ref} />;
}

export const Swipeable = React.forwardRef(forwardRef);
