import React, { useContext, useEffect, useState } from 'react'
import {
  ActivityIndicator,
  ScrollView,
  StyleProp,
  Text,
  View,
  ViewStyle,
} from 'react-native'
import { colorsV2, metricColorsV2 } from '../Colors'
import { AutoLayout } from '../components/AutoLayout'
import { CommonScreenContainer } from '../components/CommonScreenContainer'
import { ErrorBoundary } from '../components/ErrorBoundary'
import { GraphDetailScreenHeader } from '../components/GraphDetailScreenHeader'
import { GraphYAxisScale } from '../components/GraphYAxisScale'
import { HeaderNav } from '../components/HeaderNav'
import { TimeIntervalSelector } from '../components/TimeIntervalSelector'
import { useNetwork } from '../components/useNetwork'
import {
  engagementMetricIcons,
  engagementMetricLabels,
  engagementMetrics,
} from '../components/videoEngagement'
import { VideoImage } from '../components/VideoImage'
import { ScreenNames } from '../constants/ScreenNames'
import { ArtistContext } from '../contexts/ArtistContext'
import { ScreenContext } from '../contexts/ScreenContext'
import { UserContext } from '../contexts/UserContext'
import { DateData } from '../DateData'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import { useScreenRefreshControl } from '../hooks/useScreenRefreshControl'
import {
  EngagementSummary,
  useEngagementSummary,
} from '../hooks/useVideoEngagement'
import { Strings } from '../i18n'
import { ReactNavigationProps } from '../Navigation'
import { TextStylesV2 } from '../Styles'
import { defaultTimeInterval, TimeInterval } from '../types/TimeInterval'
import { Video } from '../types/types'
import { changePercent, formatCount, timeRangeInterval } from '../util'
import { formatInterval, previousDayString } from '../util/date'
import * as df from 'date-fns'
import { parseDateString } from '../util/date'
import { BarChartTouchWrapper } from '../components/BarChartTouchWrapper'
import { VerticalIndicatorBar } from '../components/VerticalIndicatorBar'
import { PercentPill } from '../components/PercentPill'
import { MarketSelectorButton } from '../components/MarketSelectorButton'
import { DateIndicator } from '../components/DateIndicator'
import { BarChart } from '../components/BarChart'
export interface VideoResponse {
  video: Video
}

/**
 *
 * Displays a vertical bar behind graph
 */
const FocusedItemIndicator: React.FC<{
  numBars: number
  selectedBarIndex: number
  style?: StyleProp<ViewStyle>
}> = ({ numBars, selectedBarIndex, style }) => {
  if (selectedBarIndex < 0) return null
  const spaceBeforeSelected = selectedBarIndex
  const spaceAfterSelected = numBars - selectedBarIndex - 1
  return (
    <View
      style={[
        {
          position: 'absolute',
          left: 0,
          right: 0,
          top: 0,
          bottom: 0,
          flexDirection: 'row',
        },
        style,
      ]}
      pointerEvents="none"
    >
      <View style={{ flex: spaceBeforeSelected }} />
      <View style={{ flex: 1 }}>
        <VerticalIndicatorBar />
      </View>
      <View style={{ flex: spaceAfterSelected }} />
    </View>
  )
}

const EngagementMetricGraph: React.FC<{
  values: DateData<number>[]
  sum: number | null
  changePercentage: number | null
  color: string
  label: string
  icon: React.ReactNode
  selectedInterval: Interval
  yAxisScaleWidth: number
  selectedDate: string | null
  style?: StyleProp<ViewStyle>
}> = ({
  values,
  sum,
  changePercentage,
  color,
  icon,
  label,
  selectedInterval,
  yAxisScaleWidth,
  selectedDate,
  style,
}) => {
  return (
    <AutoLayout
      style={[
        {
          flex: 1,
        },
        style,
      ]}
      gap={24}
    >
      <View
        style={{
          flexDirection: 'row',
          justifyContent: 'space-between',
        }}
      >
        <AutoLayout
          style={{
            flexDirection: 'row',
            alignItems: 'center',
          }}
          gap={8}
        >
          <View>{icon}</View>
          <Text style={[TextStylesV2.body, { color: colorsV2.white }]}>
            {label}
          </Text>
        </AutoLayout>

        <AutoLayout
          style={{ flexDirection: 'row', alignItems: 'center' }}
          gap={8}
        >
          <View>
            {sum != null && (
              <Text style={[TextStylesV2.body, { color: colorsV2.white }]}>
                {formatCount(sum)}
              </Text>
            )}
          </View>

          <View>
            {changePercentage != null && (
              <PercentPill percentage={changePercentage} size="small" />
            )}
          </View>
        </AutoLayout>
      </View>

      <View style={{ flex: 1, flexDirection: 'row' }}>
        <GraphYAxisScale
          data={values.map(({ data }) => data)}
          style={{ width: yAxisScaleWidth }}
          textStyle={{
            ...TextStylesV2.micro,
            ...{ color: colorsV2.metals.metal0 },
          }}
        />
        <BarChart
          data={values}
          style={{ flex: 1 }}
          barStyle={(i, item) => ({
            minHeight: 1,
            fill:
              item.date === selectedDate
                ? colorsV2.white
                : df.isWithinInterval(
                    parseDateString(item.date),
                    selectedInterval
                  )
                ? color
                : colorsV2.metals.metal1,
          })}
          barWidth={4}
          valueExtractor={(item) => item.data ?? 0}
          statusExtractor={(item) => (item.data != null ? 'full' : 'missing')}
          disablePointerEvents
        />
      </View>
    </AutoLayout>
  )
}

/**
 * A group of graphs for engagement metrics, with shared date selection
 */
const EngagementMetricGraphs: React.FC<{
  maxIntervalEngagement: EngagementSummary
  selectedIntervalEngagement: EngagementSummary
  selectedDate: string | null
  selectedInterval: Interval
  onHoverBar: (barIndex: number) => void
  onHoverBarEnd: (barIndex: number) => void
}> = ({
  maxIntervalEngagement,
  selectedIntervalEngagement,
  selectedDate,
  selectedInterval,
  onHoverBar,
  onHoverBarEnd,
}) => {
  const yAxisScaleWidth = 26

  const dateBeforeSelected =
    selectedDate !== null ? previousDayString(selectedDate) : null

  const numBars = maxIntervalEngagement.likes.currentValues.length
  const selectedBarIndex = maxIntervalEngagement.likes.currentValues.findIndex(
    ({ date }) => date === selectedDate
  )

  const metrics = engagementMetrics.map((metric) => {
    const selectedDateValue = maxIntervalEngagement[metric].currentValues?.find(
      ({ date }) => date === selectedDate
    )?.data

    const previousDayValue = maxIntervalEngagement[metric].currentValues?.find(
      ({ date }) => date === dateBeforeSelected
    )?.data

    const changePercentage =
      selectedDateValue != null &&
      previousDayValue != null &&
      previousDayValue !== 0
        ? Math.round(changePercent(selectedDateValue, previousDayValue))
        : null

    const Icon = engagementMetricIcons[metric]
    return {
      metric,
      label: engagementMetricLabels[metric],
      values: maxIntervalEngagement[metric].currentValues,
      sum:
        selectedDate === null
          ? selectedIntervalEngagement[metric].currentIntervalSum
          : selectedDateValue,
      changePercentage:
        selectedDate === null
          ? selectedIntervalEngagement[metric].changePercentage
          : changePercentage,
      color: metricColorsV2[metric],
      icon: <Icon stroke={metricColorsV2[metric]} size={24} />,
    }
  })

  return (
    <View style={{ flex: 1 }}>
      <DateIndicator
        selectedDate={selectedDate}
        desiredCenterPosition={selectedBarIndex / numBars}
        style={{ height: 32 }}
      />
      <BarChartTouchWrapper
        numBars={numBars}
        onHoverBar={onHoverBar}
        onHoverBarEnd={onHoverBarEnd}
      >
        <FocusedItemIndicator
          numBars={numBars}
          selectedBarIndex={selectedBarIndex}
          style={{ marginLeft: yAxisScaleWidth }}
        />
        <AutoLayout style={{ flex: 1 }} gap={24}>
          {metrics.map((metric, i) => (
            <EngagementMetricGraph
              key={i}
              values={metric.values}
              sum={metric.sum ?? null}
              changePercentage={metric.changePercentage}
              color={metric.color}
              label={metric.label}
              icon={metric.icon}
              selectedInterval={selectedInterval}
              selectedDate={selectedDate}
              yAxisScaleWidth={yAxisScaleWidth}
            />
          ))}
        </AutoLayout>
      </BarChartTouchWrapper>
    </View>
  )
}

const Content: React.FC<{
  videoId: string
  video: Video
  countryCode?: string
  setScrollEnabled: (enabled: boolean) => void
  onSelectTimeInterval: (timeInterval: TimeInterval) => void
}> = ({
  videoId,
  video,
  countryCode,
  setScrollEnabled,
  onSelectTimeInterval,
}) => {
  const maxInterval = defaultTimeInterval //Longest interval represented in the graph
  const maxIntervalEngagement = useEngagementSummary(
    videoId,
    timeRangeInterval(maxInterval),
    countryCode
  )
  const [selectedTimeInterval, selectTimeInterval] =
    useState<TimeInterval>(maxInterval)
  useEffect(() => {
    onSelectTimeInterval(selectedTimeInterval)
  }, [selectedTimeInterval])

  const selectedInterval = timeRangeInterval(selectedTimeInterval)
  const selectedIntervalEngagement = useEngagementSummary(
    videoId,
    selectedInterval,
    countryCode
  )
  const [selectedDate, selectDate] = useState<string | null>(null)

  return (
    <View
      style={{
        flex: 1,
        paddingHorizontal: 8,
      }}
    >
      {video && (
        <View style={{ flex: 1 }}>
          <View>
            <GraphDetailScreenHeader
              image={<VideoImage item={video} width={48} height={48} />}
              title={Strings.Shared.Engagement}
              subTitle={
                selectedDate === null ? formatInterval(selectedInterval) : ' '
              }
              dsp={video.dsp}
            />
          </View>
          <View style={{ flex: 1 }}>
            {maxIntervalEngagement !== null &&
            selectedIntervalEngagement !== null ? (
              <EngagementMetricGraphs
                maxIntervalEngagement={maxIntervalEngagement}
                selectedIntervalEngagement={selectedIntervalEngagement}
                selectedDate={selectedDate}
                selectedInterval={selectedInterval}
                onHoverBar={(barIndex) => {
                  selectDate(
                    maxIntervalEngagement.likes.currentValues[barIndex].date
                  )
                  setScrollEnabled(false)
                }}
                onHoverBarEnd={() => {
                  selectDate(null)
                  setScrollEnabled(true)
                }}
              />
            ) : (
              <ActivityIndicator style={{ flex: 1 }} />
            )}
          </View>
          <TimeIntervalSelector
            onSelectTimeInterval={selectTimeInterval}
            selectedTimeInterval={selectedTimeInterval}
          />
        </View>
      )}
    </View>
  )
}

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

  const { data, showToast, error, retry, refreshing } =
    useNetwork<VideoResponse>(
      `api/artists/${artist.sonyArtistId}/videos/${videoId}`,
      user,
      () =>
        sendAnalyticsEvent(EventType.PULL_TO_REFRESH, {
          artist_selected: artist.name,
          page: screenName,
          subject: 'user',
          verb: 'refreshed',
          object: 'video',
        })
    )
  const video = data?.video

  const { refreshControl, screenContext } = useScreenRefreshControl(
    retry,
    refreshing
  )
  const [scrollEnabled, setScrollEnabled] = useState<boolean>(true)
  return (
    <ScreenContext.Provider value={screenContext}>
      <CommonScreenContainer>
        <HeaderNav
          title={video?.videoTitle}
          showToast={showToast}
          navigation={navigation}
          style={{
            zIndex: 10,
          }}
          right={
            <MarketSelectorButton
              countryCode={countryCode}
              onPress={() => {
                navigation.navigate('MarketSelector', {
                  previousScreen: 'VideoEngagementGraph',
                })
              }}
            />
          }
        />
        <ErrorBoundary error={error} refreshControl={refreshControl}>
          <ScrollView
            refreshControl={refreshControl}
            showsVerticalScrollIndicator={false}
            contentContainerStyle={{
              flex: 1,
            }}
            scrollEnabled={scrollEnabled}
          >
            {video != null ? (
              <Content
                videoId={videoId}
                video={video}
                setScrollEnabled={setScrollEnabled}
                onSelectTimeInterval={(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',
                  })
                }}
              />
            ) : null}
          </ScrollView>
        </ErrorBoundary>
      </CommonScreenContainer>
    </ScreenContext.Provider>
  )
}
