import React, { useContext } from 'react'
import { Animated, StyleProp, StyleSheet, View, ViewStyle } from 'react-native'

import {
  ChartDsp,
  chartDsps,
  PlaylistDsp,
  playlistDsps,
  StreamingDsp,
  streamingDsps,
} from '../Consts'
import { ReactNavigationProps } from '../Navigation'
import { spaces } from '../Spaces'
import { EntityScreenStyles } from '../Styles'
import { Carousel } from '../components/Carousel'
import { CenteredActivityIndicator } from '../components/CenteredActivityIndicator'
import { CommonScreenContainer } from '../components/CommonScreenContainer'
import { DemographicsTile } from '../components/DemographicsTile'
import { EntityScreenHeader } from '../components/EntityScreenHeader'
import { EntityStreamSourcesTile } from '../components/EntityStreamSourcesTile'
import {
  ReleaseToDateTableRow,
  TimeIntervalTableRows,
} 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 { TrackChartsTile } from '../components/TrackChartsTile'
import {
  TrackComparisonSelectionModalContainer,
  useTrackComparisonSelectionModal,
} from '../components/TrackComparisonSelectionModal'
import { TrackPlaylistsTile } from '../components/TrackPlaylistsTile'
import { TrackStreamsTile } from '../components/TrackStreamsTile'
import { TrackTopStreamingCountriesTile } from '../components/TrackTopStreamingCountriesTile'
import { ScreenNames } from '../constants/ScreenNames'
import { ArtistContext } from '../contexts/ArtistContext'
import { ScreenContext } from '../contexts/ScreenContext'
import { trackDemographicsDsps } from '../graphql/Consts'
import { TrackDspId } from '../graphql/__generated__/sdk'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import { useFavorites } from '../hooks/useFavorites'
import { useScreenRefreshControl } from '../hooks/useScreenRefreshControl'
import { useTrack } from '../hooks/useTrack'
import { useTrackStreamSources } from '../hooks/useTrackStreamSources'
import { useTrackStreams } from '../hooks/useTrackStreams'
import { useTrackStreamsDemographics } from '../hooks/useTrackStreamsDemographics'
import {
  TikTokMetric,
  useTrackTikTokMetrics,
} from '../hooks/useTrackTikTokMetrics'
import { useTrackTopCountryCodes } from '../hooks/useTrackTopCountries'
import { Strings } from '../i18n'
import { defaultTimeInterval, TimeInterval } from '../types/TimeInterval'
import { Dsp } from '../types/types'
import { timeRangeInterval, useAnimateTitleOpacity } from '../util'
import { intervalToStrings } from '../util/date'
const screenName = 'Track Screen'

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

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

const TrackStreamsCarousel: React.FC<{
  isrc: string
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: StreamingDsp | 'all') => void
  onSwipe: (item: StreamingDsp | 'all') => void
}> = ({ timeInterval, onPressItem, isrc, countryCode, onSwipe }) => (
  <Carousel<StreamingDsp | 'all'>
    items={['all', ...streamingDsps]}
    renderItem={({ item }) => (
      <TrackStreamsTile
        key={item}
        isrc={isrc}
        dsp={item}
        market={countryCode}
        timeInterval={timeInterval}
        onPress={onPressItem}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

/**
 * A tile representing track stream sources for a dsp
 */
export const TrackStreamsSourcesTile: React.FC<{
  isrc: string
  dsp: StreamingDsp
  timeInterval: TimeInterval
  market: string
  onPress: () => void
  style?: StyleProp<ViewStyle>
}> = ({ isrc, dsp, timeInterval, market, onPress, style }) => {
  const { sources, error } = useTrackStreamSources(
    isrc,
    market,
    timeRangeInterval(timeInterval)
  )
  return (
    <EntityStreamSourcesTile
      dsp={dsp}
      timeInterval={timeInterval}
      onPress={onPress}
      sources={sources}
      error={error}
      title={Strings.Shared.Sources}
      style={style}
    />
  )
}

const TrackStreamSourcesCarousel: React.FC<{
  isrc: string
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: StreamingDsp) => void
  onSwipe: (item: StreamingDsp) => void
}> = ({ timeInterval, onPressItem, isrc, countryCode, onSwipe }) => (
  <Carousel<StreamingDsp>
    items={[...streamingDsps]}
    renderItem={({ item }) => (
      <TrackStreamsSourcesTile
        isrc={isrc}
        key={item}
        dsp={item}
        market={countryCode}
        timeInterval={timeInterval}
        onPress={() => onPressItem(item)}
        style={styles.tile}
      />
    )}
    onSwipe={onSwipe}
    {...carouselStyleProps}
  />
)

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

const TrackTikTokCarousel: React.FC<{
  isrc: string
  timeInterval: TimeInterval
  countryCode: string
  onPressItem: (item: TikTokMetric) => void
  onSwipe: (item: TikTokMetric) => void
}> = ({ timeInterval, onPressItem, isrc, countryCode, onSwipe }) => (
  <Carousel<TikTokMetric>
    items={['creations']}
    renderItem={({ item }) => {
      const metricTitles: Record<TikTokMetric, string> = {
        creations: Strings.TikTok.UserCreations,
        video_views: Strings.TikTok.VideoViews,
      }
      const useEntityStreams = (interval: Interval) => {
        const { metric, error } = useTrackTikTokMetrics(
          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,
        }
      }
      return (
        <EntityStreamsTile
          key={item}
          dsp="tiktok"
          timeInterval={timeInterval}
          onPress={() => onPressItem(item)}
          useEntityStreams={useEntityStreams}
          title={metricTitles[item]}
          style={styles.tile}
          infoModalTitle={Strings.TikTok.UserCreations}
          infoModalText={Strings.Info.TikTokCreations}
        />
      )
    }}
    onSwipe={onSwipe}
    {...carouselStyleProps}
    reserveIndicatorSpace
  />
)

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

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

export const TrackStreamsTable: React.FC<{
  isrc: string
  countryCode: string
  releaseDate?: string
  style?: StyleProp<ViewStyle>
}> = ({ isrc, countryCode, releaseDate, style }) => {
  const useEntityStreams = (interval: Interval) => {
    const queries = [interval].map((interval) => ({
      market: countryCode,
      interval: intervalToStrings(interval),
      dspId: null,
    }))

    const response = useTrackStreams(isrc, queries)

    return {
      streams: response?.streams?.[0],
      error: response.error,
    }
  }
  return (
    <View style={[style]}>
      <ReleaseToDateTableRow
        useEntityStreams={useEntityStreams}
        releaseDate={releaseDate}
      />
      <TimeIntervalTableRows
        useEntityStreams={useEntityStreams}
        key="intervals"
      />
    </View>
  )
}

const TrackStreamsDemographicsTile: React.FC<{
  dsp: TrackDspId
  isrc: string
  timeInterval: TimeInterval
  countryCode: string
}> = ({ dsp, timeInterval, countryCode, isrc }) => {
  const { demographics, error } = useTrackStreamsDemographics(
    isrc,
    timeRangeInterval(timeInterval),
    dsp,
    countryCode
  )

  return (
    <DemographicsTile
      dsp={dsp}
      demographics={demographics}
      error={error}
      timeInterval={timeInterval}
      style={styles.tile}
    />
  )
}

const TrackStreamsDemographicsCarousel: React.FC<{
  isrc: string
  timeInterval: TimeInterval
  countryCode: string
  onSwipe: (item: TrackDspId) => void
}> = ({ timeInterval, countryCode, isrc, onSwipe }) => {
  return (
    <Carousel<TrackDspId>
      items={trackDemographicsDsps}
      renderItem={({ item }) => (
        <TrackStreamsDemographicsTile
          key={item}
          dsp={item}
          isrc={isrc}
          timeInterval={timeInterval}
          countryCode={countryCode}
        />
      )}
      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)

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

  const track = data?.artist?.track

  const trackTopMarketCountryCodes = useTrackTopCountryCodes(isrc, timeInterval)

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

  const { setIsFavorite } = useFavorites()

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

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

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

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

  const {
    trackComparisonSelectionModalOpen,
    setTrackComparisonSelectionModalOpen,
  } = useTrackComparisonSelectionModal()

  return (
    <ScreenContext.Provider value={screenContext}>
      <CommonScreenContainer screenName={screenName}>
        <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.nameSuppl}
                  date={track.product.releaseDate}
                  image={
                    <ProductImage
                      product={track.product}
                      isExplicit={track.isExplicit}
                      size={108}
                    />
                  }
                  isFavorite={track.isFavorite}
                  setIsFavorite={(isFavorite: boolean) =>
                    setIsFavorite(isrc, isFavorite)
                  }
                  style={EntityScreenStyles.entityScreenHeader}
                  onPressCompareButton={() => {
                    setTrackComparisonSelectionModalOpen(true)
                  }}
                />
                {trackComparisonSelectionModalOpen && (
                  <TrackComparisonSelectionModalContainer
                    initialSelectedTrackIsrcs={[isrc]}
                    open={trackComparisonSelectionModalOpen}
                    onClose={() => setTrackComparisonSelectionModalOpen(false)}
                  />
                )}
                <TrackStreamsTable
                  isrc={isrc}
                  countryCode={countryCode}
                  releaseDate={track.product.releaseDate ?? undefined}
                  style={{
                    paddingBottom: 16,
                  }}
                />
                <TrackStreamsCarousel
                  isrc={isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackStreamsGraph', {
                      isrc,
                      dsp: item,
                      market: countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(isrc, 'Streams')}
                />
                <TrackStreamSourcesCarousel
                  isrc={isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackStreamSources', {
                      isrc,
                      dsp: item,
                      market: countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(isrc, 'StreamSources')}
                />
                <TrackTikTokCarousel
                  isrc={isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={() => {
                    navigation.navigate(ScreenNames.TrackTikTok, {
                      isrc,
                      market: countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForTiktokMetricSwipe(isrc)}
                />
                <TrackPlaylistsCarousel
                  isrc={isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackPlaylists', {
                      isrc: track.isrc,
                      dsp: item,
                      market: countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(isrc, 'Playlists')}
                />
                <TrackChartsCarousel
                  isrc={isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onPressItem={(item) => {
                    navigation.navigate('TrackCharts', {
                      isrc: track.isrc,
                      dsp: item,
                      market: countryCode,
                    })
                  }}
                  onSwipe={sendAnalyticsForSwipe(isrc, 'Charts')}
                />
                <TrackTopStreamingCountriesCarousel
                  isrc={isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onSwipe={sendAnalyticsForSwipe(isrc, 'TopStreamingCountries')}
                />
                <TrackStreamsDemographicsCarousel
                  isrc={track.isrc}
                  timeInterval={timeInterval}
                  countryCode={countryCode}
                  onSwipe={sendAnalyticsForSwipe(isrc, 'Demographics')}
                />
              </View>
            </Animated.ScrollView>
          ) : (
            <CenteredActivityIndicator size="large" />
          )}
        </ErrorBoundary>
      </CommonScreenContainer>
    </ScreenContext.Provider>
  )
}
