import * as df from 'date-fns'
import _ from 'lodash'
import React, { useCallback, useContext, useState } from 'react'
import { View } from 'react-native'

import { PlotColors } from '../Colors'
import { ReactNavigationProps } from '../Navigation'
import { AutoLayout } from '../components/AutoLayout'
import { CenteredActivityIndicator } from '../components/CenteredActivityIndicator'
import {
  SummaryLegendAbsoluteValueItem,
  SummaryLegendAverageViewDurationItem,
  SummaryLegendChangeItem,
  SummaryLegendChangePercentageItem,
} from '../components/SummaryLegendItem'
import { TrackDateDataFigure } from '../components/TrackDateDataFigure'
import { VideoImage } from '../components/VideoImage'
import { ScreenNames } from '../constants/ScreenNames'
import { ArtistContext } from '../contexts/ArtistContext'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import { useRegion } from '../hooks/useRegions'
import { useVideo } from '../hooks/useVideo'
import { useVideoViews } from '../hooks/useVideoViews'
import { localizedCountryName, Strings } from '../i18n'
import { streamsSummary, summaryForDate } from '../streams'
import { defaultTimeInterval, TimeInterval } from '../types/TimeInterval'
import {
  formatDateString,
  intervalToStrings,
  previousInterval as getPreviousInterval,
} from '../util/date'
import { GraphScreenContent } from './GraphScreenContent'

const Summary: React.FC<{
  value?: number
  change?: number
  changePercentage?: number
  videoDurationSeconds?: number
  averageViewDuration?: number
}> = ({
  value,
  change,
  changePercentage,
  videoDurationSeconds,
  averageViewDuration,
}) => (
  <AutoLayout gap={12}>
    <View
      style={{
        flexDirection: 'row',
        justifyContent: 'space-between',
      }}
    >
      <SummaryLegendAbsoluteValueItem
        style={{ flex: 1 }}
        label={Strings.Shared.TotalViews}
        value={value}
      />
      {change != null && (
        <SummaryLegendChangeItem
          label={Strings.Shared.TotalViewsGainLoss}
          style={{ flex: 1 }}
          change={change}
        />
      )}
    </View>
    <View
      style={{
        flexDirection: 'row',
        justifyContent: 'space-between',
      }}
    >
      <SummaryLegendAverageViewDurationItem
        style={{ flex: 1 }}
        label={Strings.Shared.AverageViewDuration}
        labelColor={PlotColors[1]}
        averageViewDurationPercentage={averageViewDuration ?? undefined}
        durationSeconds={videoDurationSeconds ?? undefined}
      />
      {changePercentage != null && (
        <SummaryLegendChangePercentageItem
          label={Strings.Shared.TotalViewsChange}
          style={{ flex: 1 }}
          changePercentage={changePercentage}
        />
      )}
    </View>
  </AutoLayout>
)

const SelectedIntervalSummary: React.FC<{
  selectedInterval: Interval
  videoId: string
  countryCode: string
}> = ({ selectedInterval, videoId, countryCode }) => {
  const currentInterval = selectedInterval
  const previousInterval = getPreviousInterval(currentInterval)

  const queries = [currentInterval, previousInterval].map((interval) => ({
    market: countryCode,
    interval: intervalToStrings(interval),
  }))

  const { views, durationSeconds } = useVideoViews(videoId, queries)

  const selectedIntervalMetrics = views?.[0]
  const previousIntervalMetrics = views?.[1]

  const selectedIntervalViewsSummary =
    selectedIntervalMetrics != null && previousIntervalMetrics
      ? streamsSummary(
          selectedIntervalMetrics.map(({ date, views }) => ({
            date,
            data: views,
          })),
          previousIntervalMetrics.map(({ date, views }) => ({
            date,
            data: views,
          }))
        )
      : null

  const averageViewDuration =
    selectedIntervalMetrics != null
      ? _.mean(
          selectedIntervalMetrics.map(
            ({ averageViewDurationPercentage }) => averageViewDurationPercentage
          )
        )
      : undefined

  return selectedIntervalViewsSummary ? (
    <Summary
      value={selectedIntervalViewsSummary?.currentIntervalStreamsSum}
      change={selectedIntervalViewsSummary?.changeNumber}
      changePercentage={
        selectedIntervalViewsSummary?.changePercentage ?? undefined
      }
      averageViewDuration={averageViewDuration}
      videoDurationSeconds={durationSeconds ?? undefined}
    />
  ) : null
}

const SelectedDateSummary: React.FC<{
  selectedInterval: Interval
  selectedBar: number | null
  videoId: string
  countryCode: string
}> = ({ selectedInterval, selectedBar, videoId, countryCode }) => {
  const queries = [selectedInterval].map((interval) => ({
    market: countryCode,
    interval: intervalToStrings(interval),
  }))

  const { views, durationSeconds } = useVideoViews(videoId, queries)

  const selectedIntervalMetrics = views?.[0]

  const selectedIntervalStreams = selectedIntervalMetrics?.map(
    ({ date, views }) => ({ date, data: views })
  )

  const selectedDate = selectedBar
    ? formatDateString(df.eachDayOfInterval(selectedInterval)[selectedBar])
    : null

  const streamsSummary =
    selectedIntervalStreams != null && selectedDate != null
      ? summaryForDate(selectedIntervalStreams, selectedDate)
      : { current: null, previous: null, changePercentage: null }

  return (
    <Summary
      value={streamsSummary?.current ?? undefined}
      change={
        streamsSummary?.current != null && streamsSummary?.previous != null
          ? streamsSummary.current - streamsSummary.previous
          : undefined
      }
      changePercentage={streamsSummary?.changePercentage ?? undefined}
      averageViewDuration={
        selectedIntervalMetrics?.find(({ date }) => date === selectedDate)
          ?.averageViewDurationPercentage ?? undefined
      }
      videoDurationSeconds={durationSeconds ?? undefined}
    />
  )
}

const Graph: React.FC<{
  selectedBar: number | null
  selectBar: (index: number | null) => void
  selectedInterval: Interval
  setScrollEnabled: (enabled: boolean) => void
  videoId: string
  countryCode: string
}> = ({
  selectedBar,
  selectBar,
  selectedInterval,
  setScrollEnabled,
  videoId,
  countryCode,
}) => {
  const queries = [selectedInterval].map((interval) => ({
    market: countryCode,
    interval: intervalToStrings(interval),
  }))

  const { views } = useVideoViews(videoId, queries)

  const selectedIntervalMetrics = views?.[0]

  if (!selectedIntervalMetrics) {
    return <CenteredActivityIndicator />
  }

  return (
    <View style={{ flex: 1 }}>
      {selectedIntervalMetrics != null ? (
        <TrackDateDataFigure
          plots={[
            {
              type: 'line',
              data: selectedIntervalMetrics.map(
                ({ averageViewDurationPercentage }) =>
                  averageViewDurationPercentage != null
                    ? Math.round(averageViewDurationPercentage)
                    : null
              ),
              axisSide: 'left',
              color: PlotColors[1],
              lineStrokeWidth: 2.5,
            },
            {
              type: 'line',
              data: selectedIntervalMetrics.map(({ views }) => views),
              axisSide: 'right',
              color: PlotColors[0],
              lineStrokeWidth: 2.5,
            },
          ]}
          axisConfig={{
            right: { legendLabel: Strings.Shared.TotalViews },
            left: {
              bounds: { min: 0 },
              legendLabel: Strings.Shared.AverageViewDuration,
            },
          }}
          selectBar={selectBar}
          selectedBar={selectedBar}
          selectedInterval={selectedInterval}
          onHoverBar={() => setScrollEnabled(false)}
          onHoverBarEnd={() => setScrollEnabled(true)}
        />
      ) : (
        <CenteredActivityIndicator />
      )}
    </View>
  )
}

export const VideoViewsGraphScreen: React.FC<
  ReactNavigationProps<ScreenNames.VideoViewsGraph>
> = ({ navigation, route }) => {
  const screenName = 'Video Views Graph Screen'
  const artist = useContext(ArtistContext)
  const { video_id: videoId } = route.params
  const countryCode = route.params.market ?? 'worldwide'

  const maxInterval = defaultTimeInterval //Longest interval represented in the graph
  const [selectedTimeInterval, selectTimeInterval] =
    useState<TimeInterval>(maxInterval)

  const region = useRegion(countryCode)
  const { data, retry, refreshing, showToast, error } = useVideo(videoId)

  const onPullToRefresh = () => {
    sendAnalyticsEvent(EventType.PULL_TO_REFRESH, {
      artist_selected: artist.name,
      page: screenName,
      subject: 'user',
      verb: 'refreshed',
      object: 'video',
    })
    retry()
  }

  const handleOnSelectTimeInterval = useCallback(
    (selectedTimeInterval) => {
      sendAnalyticsEvent(EventType.GRAPH_TIMEFRAME_CHANGED, {
        artist_selected: artist.name,
        timeframe_selected: selectedTimeInterval,
        entity_id: videoId,
        screen_name: screenName,
        subject: 'user',
        verb: 'selected',
        object: 'graph_timeframe',
      })
    },
    [artist.name, videoId]
  )

  const video = data?.artist?.video

  const title =
    countryCode === 'worldwide'
      ? Strings.Shared.ViewsWorldwide
      : region != null
      ? Strings.Shared.ViewsInMarket.replace('%s', localizedCountryName(region))
      : Strings.Shared.Views

  return video != null ? (
    <GraphScreenContent
      screenName={screenName}
      screenTitle={video.title}
      title={title}
      headerImage={<VideoImage item={video} width={48} height={48} />}
      dsp={video.dsp}
      countryCode={countryCode}
      selectedTimeInterval={selectedTimeInterval}
      selectTimeInterval={selectTimeInterval}
      onSelectTimeInterval={handleOnSelectTimeInterval}
      error={error}
      showToast={showToast}
      navigation={navigation}
      retry={onPullToRefresh}
      refreshing={refreshing}
      onPressMarketSelectorButton={() => {
        navigation.navigate('MarketSelector', {
          previousScreen: 'VideoViewsGraph',
        })
      }}
      renderSelectedDateSummary={(
        selectedInterval: Interval,
        selectedTimeInterval: TimeInterval,
        selectedBar: number | null
      ) =>
        selectedBar != null && (
          <SelectedDateSummary
            selectedInterval={selectedInterval}
            selectedBar={selectedBar}
            videoId={videoId}
            countryCode={countryCode}
          />
        )
      }
      renderSelectedIntervalSummary={(selectedInterval: Interval) => (
        <SelectedIntervalSummary
          selectedInterval={selectedInterval}
          videoId={videoId}
          countryCode={countryCode}
        />
      )}
      renderGraph={(
        selectedBar: number | null,
        selectBar: (index: number | null) => void,
        selectedInterval: Interval,
        selectedTimeInterval: TimeInterval,
        selectTimeInterval: (timeInterval: TimeInterval) => void,
        setScrollEnabled: (enabled: boolean) => void
      ) => (
        <Graph
          selectedBar={selectedBar}
          selectBar={selectBar}
          selectedInterval={selectedInterval}
          setScrollEnabled={setScrollEnabled}
          videoId={videoId}
          countryCode={countryCode}
        />
      )}
    />
  ) : null
}
