import { median } from 'd3-array'
import React, { useContext, useState } from 'react'
import { View, Text } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'

import { colors } from '../Colors'
import { ReactNavigationProps } from '../Navigation'
import { TextStyles } from '../Styles'
import { CommonScreenContainer } from '../components/CommonScreenContainer'
import { ErrorBoundary } from '../components/ErrorBoundary'
import { HeaderNav } from '../components/HeaderNav'
import { OrderDirectionButton } from '../components/OrderDirectionButton'
import { TrackListSkeleton } from '../components/Skeleton'
import { StreamsListItem } from '../components/listitems/StreamsListItem'
import { ScreenNames } from '../constants/ScreenNames'
import { ArtistContext } from '../contexts/ArtistContext'
import {
  OrderDirection,
  TrackFieldsFragment,
  TracksOrderField,
} from '../graphql/__generated__/sdk'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import { useScreenRefreshControl } from '../hooks/useScreenRefreshControl'
import { useScreenTimeInterval } from '../hooks/useScreenTimeInterval'
import { useTrackList } from '../hooks/useTrackList'
import { Strings } from '../i18n'
import { streamsSummary } from '../streams'
import { defaultTimeInterval } from '../types/TimeInterval'
import { timeRangeInterval } from '../util'

// "Top Trending" filtering logic
export function filterTopTrendingTracks<
  T extends {
    currentPeriodStreams?: number | null
    changePercentage?: number | null
  }
>(tracks: T[]) {
  const currentPeriodStreamsMedian =
    median(
      tracks
        .filter(
          ({ currentPeriodStreams }) =>
            currentPeriodStreams != null && currentPeriodStreams > 0
        )
        .map(({ currentPeriodStreams }) => currentPeriodStreams)
    ) ?? 0
  return tracks.filter(
    ({ currentPeriodStreams, changePercentage }) =>
      currentPeriodStreams &&
      currentPeriodStreams > currentPeriodStreamsMedian &&
      (changePercentage ? changePercentage >= 1 : false)
  )
}

const TracksScreenModes = [
  'streams',
  'release',
  'all',
  'favorites',
  'trending',
] as const
export type TracksScreenMode = typeof TracksScreenModes[number]

const screenName = 'Tracks Screen'

export type TrackListScreenMode = 'tiktokCreationsChange'

interface TrackListItem {
  track: TrackFieldsFragment
  changePercentage: number | null
  currentIntervalStreamsSum: number
}

const modeOptions: Record<
  TrackListScreenMode,
  {
    title: string
    titleInfoModal?: {
      title: string
      text: string
    }
    orderbyField: TracksOrderField
    displayOrderDirectionButton: boolean
    top?: React.ReactNode
    getTracks: <
      T extends {
        currentPeriodStreams?: number | null
        changePercentage?: number | null
      }
    >(
      tracks: T[]
    ) => T[]
  }
> = {
  tiktokCreationsChange: {
    title: Strings.Shared.TikTokTopTrending,
    titleInfoModal: {
      title: Strings.Shared.TikTokTopTrending,
      text: Strings.Info.TikTokCreationsTopTrending,
    },
    orderbyField: TracksOrderField.TiktokCreationsChange,
    displayOrderDirectionButton: false,
    getTracks: filterTopTrendingTracks,
  },
}

export const TrackListScreen: React.FC<
  ReactNavigationProps<ScreenNames.TrackList>
> = ({ navigation, route }) => {
  const artist = useContext(ArtistContext)

  const [timeInterval, setTimeInterval] = useScreenTimeInterval(
    defaultTimeInterval,
    {
      screenName,
      artistName: artist.name,
      entityId: artist.sonyArtistId,
    }
  )

  const options = modeOptions[route.params.mode]

  const [direction, setDirection] = useState<OrderDirection>(
    OrderDirection.Desc
  )

  const { data, error, retry, refreshing, showToast } = useTrackList(
    timeRangeInterval(timeInterval),
    {
      direction,
      field: options.orderbyField,
    }
  )

  const onPullToRefresh = () => {
    sendAnalyticsEvent(EventType.PULL_TO_REFRESH, {
      artist_selected: artist.name,
      timeframe_selected: timeInterval,
      page: 'Tracks Screen',
      subject: 'user',
      verb: 'refreshed',
      object: 'tracks',
    })
    retry()
  }

  const { refreshControl } = useScreenRefreshControl(
    onPullToRefresh,
    refreshing
  )

  const allTracks: TrackListItem[] | undefined = data?.artist?.tracks.map(
    (track) => {
      const [currentPeriodCreations, previousPeriodCreations] =
        track.tiktokMetrics.map((period) =>
          period.map(({ date, creations }) => ({
            date,
            data: creations,
          }))
        )

      const summary = streamsSummary(
        currentPeriodCreations,
        previousPeriodCreations
      )

      return {
        track,
        ...summary,
        currentPeriodStreams: summary.currentIntervalStreamsSum,
      }
    }
  )

  const tracks = allTracks != null ? options.getTracks(allTracks) : null

  return (
    <CommonScreenContainer screenName={screenName}>
      <HeaderNav
        title={options.title}
        showToast={showToast}
        navigation={navigation}
        style={{
          zIndex: 10,
        }}
        top={options.top}
        titleInfoModal={options.titleInfoModal}
        timeInterval={timeInterval}
        setTimeInterval={setTimeInterval}
      />
      <ErrorBoundary error={error} refreshControl={refreshControl}>
        <View
          style={{
            flex: 1,
            paddingHorizontal: 8,
          }}
        >
          {options.displayOrderDirectionButton && (
            <View style={{ padding: 10 }}>
              <OrderDirectionButton
                label={Strings.TikTok.UserCreations}
                orderDirection={direction}
                onPress={() =>
                  setDirection(
                    direction === OrderDirection.Asc
                      ? OrderDirection.Desc
                      : OrderDirection.Asc
                  )
                }
              />
            </View>
          )}
          {tracks != null ? (
            <FlatList
              data={tracks}
              renderItem={({ item, index }) => (
                <StreamsListItem
                  index={index}
                  track={item.track}
                  currentPeriodStreams={item.currentIntervalStreamsSum}
                  changePercentage={item.changePercentage ?? undefined}
                  onPress={() =>
                    navigation.navigate(ScreenNames.Track, {
                      isrc: item.track.isrc,
                    })
                  }
                />
              )}
              keyExtractor={(item) => item.track.isrc}
              refreshControl={refreshControl}
              ListEmptyComponent={
                <Text
                  style={{
                    ...TextStyles.tiny,
                    color: colors.metals.metal0,
                    padding: 12,
                    textAlign: 'center',
                  }}
                >
                  {Strings.Shared.NoResults}
                </Text>
              }
            />
          ) : (
            <TrackListSkeleton numItems={4} />
          )}
        </View>
      </ErrorBoundary>
    </CommonScreenContainer>
  )
}
