import React, { useContext } from 'react'
import { Animated, StyleSheet, View } from 'react-native'
import { Carousel } from '../components/Carousel'
import { CenteredActivityIndicator } from '../components/CenteredActivityIndicator'
import { CommonScreenContainer } from '../components/CommonScreenContainer'
import { EntityScreenHeader } from '../components/EntityScreenHeader'
import { EntityStreamsTable } from '../components/EntityStreamsTable'
import { EntityStreamsTile } from '../components/EntityStreamsTile'
import { ErrorBoundary } from '../components/ErrorBoundary'
import { HeaderNav } from '../components/HeaderNav'
import { MarketSelectorButton } from '../components/MarketSelectorButton'
import { ProductImage } from '../components/ProductImage'
import { StreamSourcesTile } from '../components/StreamSourcesTile'
import { TrackChartsTile } from '../components/TrackChartsTile'
import { TrackDemographicsTile } from '../components/TrackDemographicsTile'
import { TrackPlaylistsTile } from '../components/TrackPlaylistsTile'
import { TrackTopStreamingCountriesTile } from '../components/TrackTopStreamingCountriesTile'
import { ScreenNames } from '../constants/ScreenNames'
import {
  ChartDsp,
  chartDsps,
  PlaylistDsp,
  playlistDsps,
  StreamingDsp,
  streamingDsps,
} from '../Consts'
import { ArtistContext } from '../contexts/ArtistContext'
import { ScreenContext } from '../contexts/ScreenContext'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import { useFavorites } from '../hooks/useFavorites'
import { useScreenRefreshControl } from '../hooks/useScreenRefreshControl'
import { useTrack } from '../hooks/useTrack'
import { useTrackStreams } from '../hooks/useTrackStreams'
import {
  TikTokMetric,
  useTrackTikTokMetrics,
} from '../hooks/useTrackTikTokMetrics'
import { useTrackTopCountryCodes } from '../hooks/useTrackTopCountries'
import { Strings } from '../i18n'
import { ReactNavigationProps } from '../Navigation'
import { EntityScreenStyles } from '../Styles'
import { defaultTimeInterval, TimeInterval } from '../types/TimeInterval'
import { DspSlug } from '../types/types'
import { animateTitleOpacity } from '../util'
import { spaces } from '../Spaces'
import { Track } from '../types/Track'

const styles = StyleSheet.create({
  tile: { flex: 1, marginHorizontal: spaces.insets.medium },
  carousel: { marginHorizontal: -spaces.insets.medium },
  carouselIndicator: {
    paddingTop: 16,
    paddingBottom: 16,
  },
})

const carouselStyleProps = {
  style: styles.carousel,
  indicatorStyle: styles.carouselIndicator,
}

const TrackStreamsCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: StreamingDsp | 'all') => void
  onSwipe: (item: StreamingDsp | 'all') => void
}> = ({ timeInterval, onPressItem, track, countryCode, onSwipe }) => (
  <Carousel<StreamingDsp | 'all'>
    items={['all', ...streamingDsps]}
    renderItem={({ item }) => (
      <EntityStreamsTile
        key={item}
        dsp={item}
        timeInterval={timeInterval}
        onPress={() => onPressItem(item)}
        useEntityStreams={(interval: Interval) =>
          useTrackStreams(track.isrc, interval, item, countryCode)
        }
        title={Strings.Shared.Streams}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

const TrackStreamSourcesCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: StreamingDsp) => void
  onSwipe: (item: StreamingDsp) => void
}> = ({ timeInterval, onPressItem, track, countryCode, onSwipe }) => (
  <Carousel<StreamingDsp>
    items={[...streamingDsps]}
    renderItem={({ item }) => (
      <StreamSourcesTile
        key={item}
        dsp={item}
        countryCode={countryCode}
        entityId={track.isrc}
        timeInterval={timeInterval}
        onPress={() => onPressItem(item)}
        title={Strings.Shared.Sources}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

const TrackChartsCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: ChartDsp) => void
  onSwipe: (item: ChartDsp) => void
}> = ({ timeInterval, onPressItem, track, countryCode, onSwipe }) => (
  <Carousel<ChartDsp>
    items={[...chartDsps]}
    renderItem={({ item }) => (
      <TrackChartsTile
        key={item}
        isrc={track.isrc}
        dsp={item}
        countryCode={countryCode}
        timeInterval={timeInterval}
        onPress={() => onPressItem(item)}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

const TrackTikTokCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: TikTokMetric) => void
  onSwipe: (item: TikTokMetric) => void
}> = ({ timeInterval, onPressItem, track, countryCode, onSwipe }) => (
  <Carousel<TikTokMetric>
    items={['creations']}
    renderItem={({ item }) => {
      const metricTitles: Record<TikTokMetric, string> = {
        creations: Strings.TikTok.UserCreations,
        video_views: Strings.TikTok.VideoViews,
      }
      return (
        <EntityStreamsTile
          key={item}
          dsp={'tiktok'}
          timeInterval={timeInterval}
          onPress={() => onPressItem(item)}
          useEntityStreams={(interval: Interval) => {
            const { metric, error } = useTrackTikTokMetrics(
              track.isrc,
              interval,
              countryCode,
              item
            )
            // TODO: This interface for figure needs to be made generic as it's
            //       not just about streams anymore
            return {
              streams: metric,
              error,
            }
          }}
          title={metricTitles[item]}
          style={styles.tile}
          infoModalTitle={Strings.TikTok.UserCreations}
          infoModalText={Strings.Info.TikTokCreations}
        />
      )
    }}
    onSwipe={onSwipe}
    {...carouselStyleProps}
    reserveIndicatorSpace
  />
)

const TrackPlaylistsCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  onPressItem: (item: PlaylistDsp) => void
  onSwipe: (item: PlaylistDsp) => void
}> = ({ timeInterval, onPressItem, track, onSwipe }) => (
  <Carousel<PlaylistDsp>
    items={[...playlistDsps]}
    renderItem={({ item }) => (
      <TrackPlaylistsTile
        key={item}
        isrc={track.isrc}
        dsp={item}
        timeInterval={timeInterval}
        onPress={() => onPressItem(item)}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

const TrackTopStreamingCountriesCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  countryCode: string
  onSwipe: (item: StreamingDsp | 'all') => void
}> = ({ timeInterval, track, countryCode, onSwipe }) => (
  <Carousel<StreamingDsp | 'all'>
    items={['all', ...streamingDsps]}
    renderItem={({ item }) => (
      <TrackTopStreamingCountriesTile
        key={item}
        isrc={track.isrc}
        dsp={item}
        countryCode={countryCode}
        timeInterval={timeInterval}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

const TrackDemographicsCarousel: React.FC<{
  track: Track
  timeInterval: TimeInterval
  countryCode: string
  onSwipe: (item: StreamingDsp) => void
}> = ({ timeInterval, track, countryCode, onSwipe }) => (
  <Carousel<StreamingDsp>
    items={[...chartDsps]}
    renderItem={({ item }) => (
      <TrackDemographicsTile
        key={item}
        isrc={track.isrc}
        dsp={item}
        countryCode={countryCode}
        timeInterval={timeInterval}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

export const TrackScreen: React.FC<ReactNavigationProps<ScreenNames.Track>> = ({
  navigation,
  route,
}) => {
  const timeInterval = defaultTimeInterval
  const isrc = route.params.isrc
  const artist = useContext(ArtistContext)
  const { data, retry, refreshing, showToast, error } = useTrack(isrc, () =>
    sendAnalyticsEvent(EventType.PULL_TO_REFRESH, {
      artist_selected: artist.name,
      timeframe_selected: timeInterval,
      page: 'Track Screen',
      subject: 'user',
      verb: 'refreshed',
      object: 'track',
    })
  )

  const track = data?.track

  const trackTopMarketCountryCodes = useTrackTopCountryCodes(isrc, timeInterval)

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

  const { setIsFavorite } = useFavorites()

  const sendAnalyticsForSwipe =
    (track: Track, carousel: string) => (item: DspSlug) => {
      sendAnalyticsEvent(EventType.CAROUSEL_SWIPED, {
        carousel,
        screen: 'Track Screen',
        isrc: track.isrc,
        dsp: item as DspSlug,
        artist: {
          name: artist.name,
          sonyArtistId: artist.sonyArtistId,
        },
        subject: 'user',
        verb: 'swiped',
        object: 'carousel',
      })
    }

  const sendAnalyticsForTiktokMetricSwipe =
    (track: Track) => (metric: TikTokMetric) => {
      sendAnalyticsEvent(EventType.TIKTOK_METRIC_CAROUSEL_SWIPED, {
        carousel: 'TikTok Metric Carousel',
        screen: 'Track Screen',
        isrc: track.isrc,
        metric,
        artist: {
          name: artist.name,
          sonyArtistId: artist.sonyArtistId,
        },
        subject: 'user',
        verb: 'swiped',
        object: 'carousel',
      })
    }

  const countryCode = route.params.countryCode ?? 'worldwide'

  const { onScroll, titleOpacity } = animateTitleOpacity(120, 100)

  return (
    <ScreenContext.Provider value={screenContext}>
      <CommonScreenContainer>
        <HeaderNav
          title={track?.name}
          titleOpacity={titleOpacity}
          showToast={showToast}
          navigation={navigation}
          style={{
            zIndex: 10,
          }}
          right={
            <MarketSelectorButton
              countryCode={countryCode}
              onPress={() => {
                navigation.navigate('MarketSelector', {
                  previousScreen: 'Track',
                  topMarketCountryCodes: trackTopMarketCountryCodes,
                })
              }}
            />
          }
        />
        <ErrorBoundary error={error} refreshControl={refreshControl}>
          {track != null ? (
            <Animated.ScrollView
              refreshControl={refreshControl}
              showsVerticalScrollIndicator={false}
              contentContainerStyle={{ flexGrow: 1 }}
              onScroll={onScroll}
            >
              <View style={EntityScreenStyles.container}>
                <EntityScreenHeader
                  title={track.name}
                  subTitle={track.trackNameSuppl}
                  date={track.product.releaseDate}
                  image={
                    <ProductImage
                      product={track.product}
                      isExplicit={false}
                      size={108}
                    />
                  }
                  isFavorite={track.isFavorite}
                  setIsFavorite={(isFavorite: boolean) =>
                    setIsFavorite(track.isrc, isFavorite)
                  }
                  style={EntityScreenStyles.entityScreenHeader}
                />
                <EntityStreamsTable
                  entityId={track.isrc}
                  countryCode={countryCode}
                  useEntityStreams={(interval: Interval) =>
                    useTrackStreams(track.isrc, interval, 'all', countryCode)
                  }
                  releaseDate={track.product.releaseDate ?? undefined}
                  style={{
                    paddingBottom: 16,
                  }}
                />
                <TrackStreamsCarousel
                  track={track}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackStreamsGraph', {
                      isrc: track.isrc,
                      dsp: item,
                      countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(track, 'Streams')}
                />
                <TrackStreamSourcesCarousel
                  track={track}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackStreamSources', {
                      isrc: track.isrc,
                      dsp: item,
                      countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(track, 'StreamSources')}
                />
                <TrackTikTokCarousel
                  track={track}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate(ScreenNames.TrackTikTok, {
                      isrc: track.isrc,
                      countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForTiktokMetricSwipe(track)}
                />
                {
                  // Hide Playlists Tile when a specific market is selected.
                  // This should be replaced by market-specific playlist tile once supported by Delphi: https://data-analytics.atlassian.net/browse/DAE-4728
                  countryCode === 'worldwide' ? (
                    <TrackPlaylistsCarousel
                      track={track}
                      timeInterval={timeInterval}
                      onPressItem={(item) => {
                        navigation.navigate('TrackPlaylists', {
                          isrc: track.isrc,
                          dsp: item,
                        })
                      }}
                      onSwipe={sendAnalyticsForSwipe(track, 'Playlists')}
                    />
                  ) : null
                }
                <TrackChartsCarousel
                  track={track}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackCharts', {
                      isrc: track.isrc,
                      dsp: item,
                      countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(track, 'Charts')}
                />
                <TrackTopStreamingCountriesCarousel
                  track={track}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onSwipe={sendAnalyticsForSwipe(
                    track,
                    'TopStreamingCountries'
                  )}
                />

                <TrackDemographicsCarousel
                  track={track}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onSwipe={sendAnalyticsForSwipe(track, 'Demographics')}
                />
              </View>
            </Animated.ScrollView>
          ) : (
            <CenteredActivityIndicator size="large" />
          )}
        </ErrorBoundary>
      </CommonScreenContainer>
    </ScreenContext.Provider>
  )
}
