import React, { useContext } from 'react'
import * as df from 'date-fns'
import { Linking, Text, View, TouchableOpacity } from 'react-native'
import { colorsV2 } from '../Colors'
import { AutoLayout } from '../components/AutoLayout'
import { DiffNumber } from '../components/DiffNumber'
import { PlaylistImage } from '../components/PlaylistImage'
import { ProductImage } from '../components/ProductImage'
import { ScreenNames } from '../constants/ScreenNames'
import { ArtistContext } from '../contexts/ArtistContext'
import { EventType, sendAnalyticsEvent } from '../hooks/useAnalytics'
import {
  StreamsByDateResult,
  useEntityStreamsSummary,
} from '../hooks/useEntityStreams'
import { usePlaylist } from '../hooks/usePlaylist'
import { useTrack } from '../hooks/useTrack'
import { useTrackPlaylistStreams } from '../hooks/useTrackPlaylistStreams'
import { useTrackTopCountryCodes } from '../hooks/useTrackTopCountries'
import { Strings } from '../i18n'
import { ReactNavigationProps } from '../Navigation'
import { TextStylesV2 } from '../Styles'
import {
  changePercent,
  formatCount,
  playlistUrl,
  timeRangeInterval,
} from '../util'
import { formatDateString, parseDateString } from '../util/date'
import { GraphScreenContent } from './GraphScreenContent'
import { TrackDateDataFigure } from '../components/TrackDateDataFigure'
import { useTrackPlaylistPositions } from '../hooks/useTrackPlaylistPositions'
import { PositionChangeAndArrow } from '../components/PositionChangeAndArrow'
import { defaultTimeInterval, TimeInterval } from '../types/TimeInterval'
import { dateDataNumberRange } from '../DateData'

export const SummaryItem: React.FC<{
  label: string
  labelColor?: string
}> = ({ label, labelColor, children }) => (
  <View style={{ flex: 1 }}>
    <Text
      style={{
        ...TextStylesV2.tiny,
        ...{ color: labelColor ?? colorsV2.metals.metal0 },
      }}
    >
      {label}
    </Text>
    {children}
  </View>
)

export const PositionChange: React.FC<{
  position: {
    current: number | null
    previous: number | null
  }
}> = ({ position }) => {
  return position.current != null && position.previous != null ? (
    position.current !== position.previous ? (
      <PositionChangeAndArrow
        currentValue={position.current}
        previousValue={position.previous}
        invertDirection
      />
    ) : (
      <Text style={[TextStylesV2.bodyBold, { color: colorsV2.white }]}>
        {Strings.Shared.NoChange}
      </Text>
    )
  ) : (
    <Text style={[TextStylesV2.bodyBold, { color: colorsV2.white }]}>
      {Strings.Shared.NotApplicable}
    </Text>
  )
}

/**
 *
 * Display information for the currently selected day
 */
export const TrackPlaylistDaySummary: React.FC<{
  streams: {
    current: number
    changePercentage: number | null
  }
  position?: {
    current: number | null
    previous: number | null
  }
}> = ({ streams, position }) => {
  return (
    <View>
      <View
        style={{
          flexDirection: 'row',
          justifyContent: 'space-between',
          marginBottom: 12,
        }}
      >
        <SummaryItem label={Strings.Shared.TotalStreams}>
          <Text style={[TextStylesV2.bodyBold, { color: colorsV2.white }]}>
            {formatCount(streams.current)}
          </Text>
        </SummaryItem>
        {streams.changePercentage != null && (
          <SummaryItem label={Strings.Shared.Change}>
            {streams.changePercentage != null && (
              <DiffNumber
                value={streams.changePercentage}
                size="large"
                type="percentage"
              />
            )}
          </SummaryItem>
        )}
      </View>
      <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
        <SummaryItem
          label={Strings.Shared.PositionInPlaylist}
          labelColor={colorsV2.platform.apple}
        >
          {position != null ? (
            <Text style={[TextStylesV2.bodyBold, { color: colorsV2.white }]}>
              {position?.current != null
                ? `#${formatCount(position.current)}`
                : Strings.Shared.NotApplicable}
            </Text>
          ) : null}
        </SummaryItem>
        <SummaryItem
          label={Strings.Shared.PositionChange}
          labelColor={colorsV2.platform.apple}
        >
          {position != null ? <PositionChange position={position} /> : null}
        </SummaryItem>
      </View>

      {position == null ? (
        <Text
          style={[
            TextStylesV2.bodySmall,
            {
              color: colorsV2.white,
              marginTop: 12,
            },
          ]}
        >
          {Strings.TrackPlaylistScreen.PressTheChartToSeePositionInPlaylist}
        </Text>
      ) : null}
    </View>
  )
}

export const TrackPlaylistIntervalSummary: React.FC<{
  selectedInterval: Interval
  useEntityStreams: (interval: Interval) => StreamsByDateResult
}> = ({ selectedInterval, useEntityStreams }) => {
  const selectedIntervalSummary = useEntityStreamsSummary(
    selectedInterval,
    useEntityStreams
  )?.data

  const selectedDateStreams = selectedIntervalSummary?.currentIntervalStreamsSum
  const selectedDateStreamsChangePercentage =
    selectedIntervalSummary?.changePercentage

  return selectedDateStreams != null ? (
    <TrackPlaylistDaySummary
      streams={{
        current: selectedDateStreams,
        changePercentage:
          selectedDateStreamsChangePercentage != null
            ? Math.round(selectedDateStreamsChangePercentage)
            : null,
      }}
    />
  ) : null
}

export const TrackPlaylistScreen: React.FC<
  ReactNavigationProps<ScreenNames.TrackPlaylist>
> = ({ navigation, route }) => {
  const screenName = 'Track Playlist Screen'
  const { isrc, playlistId } = route.params
  const artist = useContext(ArtistContext)
  const countryCode = route.params.countryCode ?? 'worldwide'

  const { data, retry, refreshing, showToast, error } = useTrack(isrc, () =>
    sendAnalyticsEvent(EventType.PULL_TO_REFRESH, {
      artist_selected: artist.name,
      page: screenName,
      subject: 'user',
      verb: 'refreshed',
      object: 'playlist',
    })
  )

  const track = data?.track

  const { data: playlistData } = usePlaylist(playlistId)
  const playlist = playlistData?.playlist
  const playlistName = playlist?.name ?? ''
  const dsp = playlist?.dsp?.slug
  const trackTopMarketCountryCodes = useTrackTopCountryCodes(
    isrc,
    defaultTimeInterval
  )
  const maxInterval = defaultTimeInterval //Longest interval represented in the bar graph
  const useTrackPlaylistStreamsForInterval =
    track != null
      ? (interval: Interval) =>
          useTrackPlaylistStreams(track.isrc, playlistId, interval, countryCode)
      : null
  const maxIntervalStreams =
    useTrackPlaylistStreamsForInterval != null
      ? useEntityStreamsSummary(
          timeRangeInterval(maxInterval),
          useTrackPlaylistStreamsForInterval
        )?.data?.currentIntervalStreams
      : null

  const foo = useTrackPlaylistPositions(
    isrc,
    playlistId,
    timeRangeInterval(maxInterval)
  )

  const maxIntervalPositions = foo?.positions

  return (
    <GraphScreenContent
      screenTitle={track?.name}
      title={playlistName}
      headerImage={
        track != null && playlist != null ? (
          <AutoLayout style={{ flexDirection: 'row' }} gap={8}>
            <ProductImage
              product={track.product}
              isExplicit={false}
              size={48}
            />

            <TouchableOpacity
              onPress={() => {
                const url = playlistUrl(playlist)
                if (url) {
                  sendAnalyticsEvent(EventType.PLAYLIST_OPENED, {
                    isrc: track.isrc,
                    playlist_name: playlist.name,
                    dsp: playlist.dsp.slug,
                    url,
                    subject: 'user',
                    verb: 'opened',
                    object: 'playlist',
                  })

                  Linking.openURL(url)
                }
              }}
            >
              <PlaylistImage playlist={playlist} imageSize={48} />
            </TouchableOpacity>
          </AutoLayout>
        ) : null
      }
      dsp={dsp ?? 'all'}
      countryCode={countryCode}
      onSelectTimeInterval={(selectedTimeInterval) => {
        sendAnalyticsEvent(EventType.GRAPH_TIMEFRAME_CHANGED, {
          artist_selected: artist.name,
          timeframe_selected: selectedTimeInterval,
          entity_id: isrc,
          screen_name: screenName,
          subject: 'user',
          verb: 'selected',
          object: 'graph_timeframe',
        })
      }}
      error={error}
      showToast={showToast}
      navigation={navigation}
      retry={retry}
      refreshing={refreshing}
      onPressMarketSelectorButton={() => {
        navigation.navigate('MarketSelector', {
          previousScreen: 'TrackPlaylist',
          topMarketCountryCodes: trackTopMarketCountryCodes,
        })
      }}
      renderSelectedDateSummary={(selectedDate: string) => {
        const selectedDateStreams =
          maxIntervalStreams?.find(({ date }) => date === selectedDate)?.data ??
          0
        const dayBeforeSelectedDateStreams = selectedDate
          ? maxIntervalStreams?.find(
              ({ date }) =>
                date ===
                formatDateString(df.subDays(parseDateString(selectedDate), 1))
            )?.data ?? null
          : null
        const changePercentage =
          selectedDateStreams != null &&
          dayBeforeSelectedDateStreams != null &&
          dayBeforeSelectedDateStreams != 0
            ? Math.round(
                changePercent(selectedDateStreams, dayBeforeSelectedDateStreams)
              )
            : null

        const selectedDatePosition =
          maxIntervalPositions?.find(({ date }) => date === selectedDate)
            ?.data ?? null
        const dayBeforeSelectedDatePosition = selectedDate
          ? maxIntervalPositions?.find(
              ({ date }) =>
                date ===
                formatDateString(df.subDays(parseDateString(selectedDate), 1))
            )?.data ?? null
          : null

        return (
          <TrackPlaylistDaySummary
            streams={{ current: selectedDateStreams, changePercentage }}
            position={{
              current: selectedDatePosition,
              previous: dayBeforeSelectedDatePosition,
            }}
          />
        )
      }}
      renderSelectedIntervalSummary={(selectedInterval: Interval) =>
        useTrackPlaylistStreamsForInterval != null ? (
          <TrackPlaylistIntervalSummary
            selectedInterval={selectedInterval}
            useEntityStreams={useTrackPlaylistStreamsForInterval}
          />
        ) : null
      }
      renderGraph={(
        selectedDate: string | null,
        selectDate: (date: string | null) => void,
        selectedInterval: Interval,
        selectedTimeInterval: TimeInterval,
        selectTimeInterval: (timeInterval: TimeInterval) => void,
        setScrollEnabled: (enabled: boolean) => void
      ) => {
        if (maxIntervalStreams == null || maxIntervalPositions == null) {
          return null
        } else {
          // maxRange can be null if interval is full of nulls
          const maxRange = dateDataNumberRange(maxIntervalPositions)?.max ?? 0

          return (
            <View style={{ flex: 1 }}>
              <TrackDateDataFigure
                maxIntervalBar={maxIntervalStreams}
                maxIntervalLine={maxIntervalPositions}
                lineAxisConfig={{
                  bounds: {
                    min: 1,
                    // Add +2 to domain as it is used to calculate the axes of
                    // the plots, otherwise when max === min, we could not
                    // align the plot into the figure as there would be no
                    // scale on that axis. Use +2 instead of +1 in order to
                    // have at least 3 ticks (e.g. 1 + 2 => ticks: 1, 2, 3) to
                    // make figures more visually pleasing
                    max: maxRange + 2,
                  },
                  fixedLabels: { min: 1 },
                }}
                selectDate={selectDate}
                selectedDate={selectedDate}
                selectedTimeInterval={selectedTimeInterval}
                selectTimeInterval={selectTimeInterval}
                selectedInterval={selectedInterval}
                onHoverBar={() => setScrollEnabled(false)}
                onHoverBarEnd={() => setScrollEnabled(true)}
                lineReverse={true}
              />
            </View>
          )
        }
      }}
    />
  )
}
