import _ from 'lodash'
import React, { useContext, useState } from 'react'
import {
  View,
  StyleSheet,
  Animated,
  useWindowDimensions,
  Text,
  ScrollView,
  ActivityIndicator,
  RefreshControlProps,
} from 'react-native'

import { colors, DspColors } from '../Colors'
import { SocialMedia, socialMedias } from '../Consts'
import { ReactNavigationProps } from '../Navigation'
import { Styles, TextStyles } from '../Styles'
import { ChangePlusMinusAndNumber } from '../components/ChangePlusMinusAndNumber'
import { CommonScreenContainer } from '../components/CommonScreenContainer'
import { ErrorBoundary } from '../components/ErrorBoundary'
import { Filters } from '../components/Filters'
import { GraphDateLabels } from '../components/GraphDateLabels'
import { HeaderNav } from '../components/HeaderNav'
import { Number } from '../components/Number'
import { SocialIcon } from '../components/SocialIcon'
import { LineFigure } from '../components/figures/LineFigure'
import {
  useSocial,
  DSPS,
  SocialData,
  isSocialMedia,
} from '../components/useSocial'
import { ScreenNames } from '../constants/ScreenNames'
import { ArtistContext } from '../contexts/ArtistContext'
import {
  EventType,
  sendAnalyticsEvent,
  useAnalytics,
} from '../hooks/useAnalytics'
import { useAnimatedChart } from '../hooks/useAnimatedChart'
import { NetworkRequest } from '../hooks/useNetwork'
import { useScreenRefreshControl } from '../hooks/useScreenRefreshControl'
import { useScreenTimeInterval } from '../hooks/useScreenTimeInterval'
import { defaultTimeInterval, TimeInterval } from '../types/TimeInterval'
import { BarLabel } from '../types/types'
import {
  daysInTimeRange,
  formatCount,
  labelsForInterval,
  timeRangeDates,
} from '../util'

export const styles = StyleSheet.create({
  container: {
    flexGrow: 1,
  },
  social: {
    flexGrow: 1,
    marginVertical: 16,
  },
  followers: {
    flexGrow: 1,
    alignContent: 'flex-end',
  },
  graphContainer: {
    flexGrow: 1,
  },
  labelContainer: {
    paddingTop: 8,
  },
  changeNumber: {
    ...TextStyles.h3,
  },
  arrowContainer: {
    paddingHorizontal: 10,
  },
  socialTop: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 10,
  },
  numberContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  label: {
    ...TextStyles.bodyMedium,
  },
})

const padding = Styles.screenHorizontalPadding.paddingHorizontal

const FollowersLabel = ({
  selection,
  labels,
  row,
}: {
  selection?: number
  labels?: BarLabel[]
  row?: SocialData
}) => {
  const label = selection != null && labels != null ? labels[selection] : null
  const rowData =
    selection != null && row != null ? row.data?.[selection] : null
  return (
    <View style={styles.labelContainer}>
      <View style={{ marginLeft: 8 }}>
        <Text style={[styles.label, { color: colors.metals.metal1 }]}>
          {label?.weekday ?? ' '}
        </Text>
        <Text style={[styles.label, { color: colors.metals.metal1 }]}>
          {label?.date ?? ' '}
        </Text>
        <Text style={[TextStyles.body, { color: colors.midWhite }]}>
          {rowData ? formatCount(rowData) : ' '}
        </Text>
      </View>
    </View>
  )
}

export const FollowersScreen: React.FC<
  ReactNavigationProps<ScreenNames.Followers>
> = ({ navigation, route }) => {
  const screenName = 'Followers Screen'
  const artist = useContext(ArtistContext)
  const initialDsp = route.params.dsp_slug

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

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

  const { refreshControl } = useScreenRefreshControl(
    onPullToRefresh,
    request.refreshing
  )

  const socialData = request.data?.filter(isSocialMedia)

  return (
    <CommonScreenContainer screenName={screenName}>
      <View
        style={{
          flex: 1,
          backgroundColor: colors.metals.metal3,
        }}
      >
        <HeaderNav
          title="Social"
          navigation={navigation}
          showToast={request.showToast}
          style={{
            backgroundColor: colors.black,
          }}
          titleStyle={{
            textTransform: 'capitalize',
          }}
          timeInterval={timeInterval}
          setTimeInterval={setTimeInterval}
        />
        <View style={{ flex: 1, ...Styles.screenHorizontalPadding }}>
          <ErrorBoundary error={request.error} refreshControl={refreshControl}>
            <Content
              {...{ navigation, route }}
              {...request}
              data={socialData}
              initialDsp={initialDsp}
              timeInterval={timeInterval}
              refreshControl={refreshControl}
            />
          </ErrorBoundary>
        </View>
      </View>
    </CommonScreenContainer>
  )
}

const Content: React.FC<
  NetworkRequest<SocialData[]> & {
    initialDsp: SocialMedia
    timeInterval: TimeInterval
    refreshControl: React.ReactElement<RefreshControlProps>
  }
> = ({ initialDsp, data, refreshControl, timeInterval }) => {
  const windowWidth = useWindowDimensions().width
  const width = windowWidth - padding * 2
  const days = daysInTimeRange(timeInterval)
  const { startDate, endDate } = timeRangeDates(timeInterval)
  const labels = labelsForInterval(startDate, endDate)
  const [scrolling, setScrolling] = useState<boolean>(false)
  const { selection, viewProps } = useAnimatedChart(days, width, scrolling)

  const dataForDsp = (data: SocialData[], dsp: string) =>
    data.find(({ dspSlug }) => dspSlug === dsp)

  const useSocialAnalytics = (socialMedia: string) =>
    useAnalytics(
      EventType.SOCIAL_MEDIA_DETAILS_VIEWED,
      {
        social_media_type: socialMedia,
        subject: 'user',
        verb: 'viewed',
        object: 'social_media',
      },
      true,
      timeInterval
    )

  return data != null ? (
    <ScrollView
      contentContainerStyle={styles.container}
      refreshControl={refreshControl}
      scrollEnabled={selection == null}
      onScrollBeginDrag={() => setScrolling(true)}
      onScrollEndDrag={() => setScrolling(false)}
    >
      <View style={styles.social}>
        <Filters<SocialMedia>
          selectedFilter={initialDsp}
          filters={Object.values(socialMedias).map((key) => ({
            key,
            label: key,
            disabled: dataForDsp(data, key)?.current == null,
          }))}
          onLoad={useSocialAnalytics}
        >
          {(dsp) => {
            const row = dataForDsp(data, dsp)

            if (row == null) {
              return null
            }

            const { current, previous } = row
            const textStyle = _.omit(styles.changeNumber, 'color')
            const changeNumber =
              current === null || previous === null
                ? undefined
                : current - previous

            return (
              <View key={dsp} style={styles.followers}>
                <SocialIcon dspSlug={dsp} />
                <Text
                  style={{
                    ...TextStyles.body,
                    textTransform: 'capitalize',
                  }}
                >
                  {fullTitle(dsp)}
                </Text>
                <View style={styles.numberContainer}>
                  {current ? (
                    <Number number={current} style={textStyle} />
                  ) : null}
                  <ChangePlusMinusAndNumber
                    changeNumber={changeNumber}
                    textStyle={textStyle}
                  />
                </View>
                <FollowersLabel
                  {...{
                    selection,
                    labels,
                    row,
                  }}
                />
                <Animated.View style={styles.graphContainer} {...viewProps}>
                  <LineFigure
                    data={[
                      {
                        yValues: row.data,
                        strokeColor: DspColors[dsp],
                      },
                    ]}
                    strokeWidth={4}
                    selection={selection}
                  />
                </Animated.View>
                <GraphDateLabels startDate={startDate} endDate={endDate} />
              </View>
            )
          }}
        </Filters>
      </View>
    </ScrollView>
  ) : (
    <ActivityIndicator style={{ flex: 1 }} size="large" />
  )
}

function fullTitle(dsp: string) {
  return DSPS.find(({ slug }) => slug === dsp)?.title ?? 'followers'
}
