import React, { useContext, useRef, useState } from 'react'
import { Animated, Text, TouchableOpacity, View, ViewStyle } from 'react-native'
import { colorsV2 } from '../Colors'
import { BarSelect } from '../components/BarSelect'
import { CommonScreenContainer } from '../components/CommonScreenContainer'
import { ErrorBoundary } from '../components/ErrorBoundary'
import { GraphDetailScreenHeader } from '../components/GraphDetailScreenHeader'
import { HeaderNav } from '../components/HeaderNav'
import { PlaylistTypeSelectorModal } from '../components/PlaylistTypeSelectorModal'
import { ProductImage } from '../components/ProductImage'
import { TrackPlaylist } from '../components/TrackPlaylistV2'
import { ScreenNames } from '../constants/ScreenNames'
import { dspNames, PlaylistDsp } from '../Consts'
import { ArtistContext } from '../contexts/ArtistContext'
import { ScreenContext } from '../contexts/ScreenContext'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import { useScreenRefreshControl } from '../hooks/useScreenRefreshControl'
import { useTrack } from '../hooks/useTrack'
import { useTrackPlaylistsData } from '../hooks/useTrackPlaylistsData'
import { Strings } from '../i18n'
import { ReactNavigationProps } from '../Navigation'
import { playlistTrackPositionsForPlaylistType } from '../playlists'
import { TextStylesV2 } from '../Styles'
import { AmaPlaylistType } from '../types/Playlist'
import { defaultTimeInterval } from '../types/TimeInterval'
import {
  PlaylistTrackPosition,
  PlaylistTrackPositionWithCurrentStreams,
} from '../types/types'
import { notEmpty, timeRangeInterval } from '../util'

export const PlaylistTypeSelectorButton: React.FC<{
  playlistType: AmaPlaylistType | null
  onPress: () => void
}> = ({ playlistType, onPress }) => (
  <TouchableOpacity
    style={{
      height: 48,
      flexDirection: 'row',
      alignItems: 'center',
      borderWidth: 2,
      borderColor: colorsV2.metals.metal1,
      borderRadius: 8,
      paddingVertical: 8,
      paddingHorizontal: 12,
    }}
    onPress={onPress}
  >
    <Text
      style={[
        TextStylesV2.body,
        {
          color: colorsV2.white,
          flex: 1,
        },
      ]}
    >
      {Strings.PlaylistTypes[playlistType ?? 'all']}
    </Text>
    <Text
      style={[
        TextStylesV2.body,
        {
          color: colorsV2.white,
          fontSize: 12,
          textAlign: 'center',
          width: 24,
          lineHeight: 24,
        },
      ]}
    >
      ▼
    </Text>
  </TouchableOpacity>
)

const sortOptions = ['streams', 'position'] as const
type PlaylistSortingOrder = typeof sortOptions[number]

export const PlaylistListHeader: React.FC<{
  numPlaylists: number
  sorting: PlaylistSortingOrder
  toggleSort: (order: PlaylistSortingOrder) => void
  setPlaylistTypeModalOpen: (open: boolean) => void
  playlistType: AmaPlaylistType | null
  style?: Animated.AnimatedProps<ViewStyle>
}> = ({
  numPlaylists,
  sorting,
  toggleSort,
  setPlaylistTypeModalOpen,
  playlistType,
  style,
}) => (
  <Animated.View style={style}>
    <PlaylistTypeSelectorButton
      playlistType={playlistType}
      onPress={() => {
        setPlaylistTypeModalOpen(true)
      }}
    />
    <View
      style={{
        flexDirection: 'column',
        justifyContent: 'space-between',
      }}
    >
      <BarSelect<PlaylistSortingOrder>
        options={sortOptions}
        value={sorting}
        onChange={toggleSort}
        translateLabel={(order) => {
          switch (order) {
            case 'position':
              return `${Strings.Shared.Position}  ↓`
            case 'streams':
              return `${Strings.Shared.Streams}  ↓`
          }
        }}
      />
      <Text style={[TextStylesV2.small, { color: colorsV2.white }]}>
        {numPlaylists === 1
          ? Strings.Shared.OnePlaylistSingular
          : Strings.Shared.NPlaylistsPlural.replace(
              '%d',
              numPlaylists.toString()
            )}
      </Text>
    </View>
  </Animated.View>
)

export const PlaylistListEmpty: React.FC<{
  playlistType: AmaPlaylistType | null
  dsp: PlaylistDsp
}> = ({ playlistType, dsp }) => (
  <View
    style={{
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      padding: 24,
    }}
  >
    <Text
      style={[
        TextStylesV2.body,
        { color: colorsV2.white, textAlign: 'center' },
      ]}
    >
      {Strings.PlaylistsEmpty.replace(
        '%s',
        [
          dspNames[dsp],
          playlistType ? Strings.PlaylistTypes[playlistType] : null,
        ]
          .filter(notEmpty)
          .join(' ')
      )}
    </Text>
  </View>
)

export const TrackPlaylistsScreen: React.FC<
  ReactNavigationProps<ScreenNames.TrackPlaylists>
> = ({ navigation, route }) => {
  const screenName = 'Track Playlists Screen'
  const { isrc, dsp } = route.params
  const artist = useContext(ArtistContext)

  const { data, retry, refreshing, showToast, error } = useTrack(isrc, () =>
    sendAnalyticsEvent(EventType.PULL_TO_REFRESH, {
      artist_selected: artist.name,
      page: screenName,
      subject: 'user',
      verb: 'refreshed',
      object: 'track',
    })
  )
  const track = data?.track

  const [scrollEnabled, setScrollEnabled] = useState<boolean>(true)

  const { refreshControl, screenContext } = useScreenRefreshControl(
    retry,
    refreshing
  )

  const interval = timeRangeInterval(defaultTimeInterval)

  const x = useTrackPlaylistsData(isrc, interval, dsp, null)

  const [playlistType, setPlaylistType] = useState<AmaPlaylistType | null>(null)
  const [playlistTypeModalIsOpen, setPlaylistTypeModalOpen] = useState(false)

  const [sorting, setSorting] = useState<PlaylistSortingOrder>('streams')

  const allPlaylistTrackPositions = x.data?.playlistTrackPositions

  /**
   *  Current position for playlists of type "algorithimic" should not be displayed, and should be sorted last
   */
  const normalizedPosition = (
    playlistTrackPosition: PlaylistTrackPosition
  ): number => {
    return playlistTrackPosition.playlist.playlistType === 'algorithmic'
      ? Infinity
      : playlistTrackPosition.current ?? Infinity
  }
  const sortByStreams = (
    a: PlaylistTrackPositionWithCurrentStreams,
    b: PlaylistTrackPositionWithCurrentStreams
  ) => b.data - a.data

  const sortByCurrentPosition = (
    a: PlaylistTrackPositionWithCurrentStreams,
    b: PlaylistTrackPositionWithCurrentStreams
  ) =>
    normalizedPosition(a.item) === normalizedPosition(b.item)
      ? sortByStreams(a, b)
      : normalizedPosition(a.item) - normalizedPosition(b.item)

  const sortingFn =
    sorting === 'streams' ? sortByStreams : sortByCurrentPosition
  const playlistTrackPositions =
    allPlaylistTrackPositions != null
      ? playlistTrackPositionsForPlaylistType(
          allPlaylistTrackPositions,
          playlistType
        ).sort(sortingFn)
      : null

  const scrollY = useRef(new Animated.Value(0)).current
  const headerHeight = 132
  const minScroll = 0
  const clampedScrollY = scrollY.interpolate({
    inputRange: [minScroll, minScroll + 1],
    outputRange: [0, 1],
    extrapolateLeft: 'clamp',
  })
  const minusScrollY = Animated.multiply(clampedScrollY, -1)
  const headerTranslate = Animated.diffClamp(minusScrollY, -headerHeight, 0)

  return (
    <ScreenContext.Provider value={screenContext}>
      <CommonScreenContainer>
        <ErrorBoundary error={error} refreshControl={refreshControl}>
          <HeaderNav
            style={{
              // Ensures header is over the hidden (scrolled-up) PlaylistListHeader
              zIndex: 1,
            }}
            title={track?.name ?? ''}
            showToast={showToast}
            navigation={navigation}
          />
          <View
            style={{
              flex: 1,
              paddingHorizontal: 8,
            }}
          >
            <GraphDetailScreenHeader
              image={
                track != null ? (
                  <ProductImage
                    product={track.product}
                    isExplicit={false}
                    size={48}
                  />
                ) : null
              }
              title={Strings.Shared.Playlists}
              dsp={dsp}
            />
            {playlistTrackPositions != null && (
              <View style={{ flex: 1, zIndex: -1 }}>
                <Animated.FlatList
                  renderItem={({ item, index }) => (
                    <TrackPlaylist
                      key={item.item.playlist.sonyPlaylistId}
                      showDetails={true}
                      playlist={item}
                      style={{
                        padding: 12,
                        backgroundColor: colorsV2.metals.metal2,
                        borderRadius: 8,
                        marginBottom: 8,
                      }}
                      onPress={() => {
                        navigation.navigate('TrackPlaylist', {
                          isrc,
                          playlistId: item.item.playlist.sonyPlaylistId,
                        })
                      }}
                    />
                  )}
                  keyExtractor={(item, index) =>
                    item.item.playlist.sonyPlaylistId
                  }
                  data={playlistTrackPositions}
                  contentContainerStyle={
                    playlistTrackPositions.length === 0
                      ? { flex: 1 }
                      : { paddingTop: headerHeight }
                  }
                  ListEmptyComponent={
                    <PlaylistListEmpty playlistType={playlistType} dsp={dsp} />
                  }
                  onScroll={Animated.event(
                    [{ nativeEvent: { contentOffset: { y: scrollY } } }],
                    { useNativeDriver: true }
                  )}
                  scrollEventThrottle={1}
                  refreshControl={refreshControl}
                />
                <PlaylistListHeader
                  numPlaylists={playlistTrackPositions.length}
                  sorting={sorting}
                  toggleSort={setSorting}
                  setPlaylistTypeModalOpen={setPlaylistTypeModalOpen}
                  playlistType={playlistType}
                  style={{
                    height: headerHeight,
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    right: 0,
                    backgroundColor: colorsV2.black,
                    transform: [{ translateY: headerTranslate }],
                  }}
                />
              </View>
            )}
            <PlaylistTypeSelectorModal
              isOpen={playlistTypeModalIsOpen}
              playlistType={playlistType}
              setPlaylistType={setPlaylistType}
              setIsOpen={setPlaylistTypeModalOpen}
            />
          </View>
        </ErrorBoundary>
      </CommonScreenContainer>
    </ScreenContext.Provider>
  )
}
