import * as df from 'date-fns'
import React from 'react'
import { Text, View } from 'react-native'

import { colors, DspColors } from '../Colors'
import { Dsp, StreamingDsp, streamingDsps } from '../Consts'
import { NavigationProp } from '../Navigation'
import { TextStyles } from '../Styles'
import { ChangePlusMinusAndPercent } from '../components/ChangePlusMinusAndPercent'
import { ScreenNames } from '../constants/ScreenNames'
import { IntervalSummary } from '../hooks/useEntityStreams'
import { NetworkError } from '../hooks/useNetwork'
import { GraphScreenContent } from '../screens/GraphScreenContent'
import { summaryForDate } from '../streams'
import { TimeInterval } from '../types/TimeInterval'
import { changePercent, formatCount } from '../util'
import { formatDateString } from '../util/date'
import { CenteredActivityIndicator } from './CenteredActivityIndicator'
import { ContextMenuItem } from './ContextMenuModal'
import { DspStreams } from './DspStreams'
import {
  SummaryLegendAbsoluteValueItem,
  SummaryLegendChangeItem,
  SummaryLegendChangePercentageItem,
} from './SummaryLegendItem'
import { TrackDateDataFigure } from './TrackDateDataFigure'
import { PlotConfig } from './figures/BarAndLineFigure'

/**
 * Display information for the currently selected time interval
 */
export const IntervalSummaryChanges: React.FC<{
  changePercentage: number | null
  currentIntervalStreamsSum: number
}> = ({ changePercentage, currentIntervalStreamsSum }) => {
  return (
    <View>
      <Text style={[TextStyles.h3, { color: colors.white }]}>
        {formatCount(currentIntervalStreamsSum)}
      </Text>
      {changePercentage !== null && (
        <ChangePlusMinusAndPercent changePercentage={changePercentage} />
      )}
    </View>
  )
}

/**
 *
 * Display information for the currently selected day
 */
export const DaySummary: React.FC<{
  currentValue: number | null
  previousValue: number | null
  currentValuePerDsp:
    | {
        dsp: StreamingDsp
        streams: number
      }[]
    | null
  totalLabel: string
  gainLossLabel: string
  changeLabel: string
}> = ({
  currentValue,
  previousValue,
  currentValuePerDsp,
  totalLabel,
  gainLossLabel,
  changeLabel,
}) => {
  return (
    <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
      <View style={{ flex: 1 }}>
        <SummaryLegendAbsoluteValueItem
          label={totalLabel}
          value={currentValue ?? undefined}
        />
        {currentValuePerDsp != null ? (
          <View>
            {currentValuePerDsp?.map(({ dsp, streams }) => (
              <DspStreams key={dsp} dsp={dsp} streams={streams} gap={21} />
            ))}
          </View>
        ) : null}
      </View>
      {previousValue != null ? (
        <View style={{ flex: 1 }}>
          <SummaryLegendChangeItem
            label={gainLossLabel}
            style={{ marginBottom: 15 }}
            change={
              currentValue != null && previousValue != null
                ? currentValue - previousValue
                : undefined
            }
          />
          <SummaryLegendChangePercentageItem
            label={changeLabel}
            changePercentage={
              currentValue != null &&
              previousValue != null &&
              previousValue !== 0
                ? Math.round(changePercent(currentValue, previousValue))
                : undefined
            }
          />
        </View>
      ) : null}
    </View>
  )
}

const SelectedDateSummary: React.FC<{
  selectedInterval: Interval
  selectedTimeInterval: TimeInterval
  selectedBar: number | null
  dsp: Dsp | 'all'
  useEntityStreams: (interval: Interval, dsp: Dsp | 'all') => IntervalSummary[]
  totalLabel: string
  gainLossLabel: string
  changeLabel: string
}> = ({
  selectedInterval,
  selectedBar,
  dsp,
  useEntityStreams,
  totalLabel,
  gainLossLabel,
  changeLabel,
}) => {
  const [streams] = useEntityStreams(selectedInterval, dsp)

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

  const streamsSummary =
    streams && selectedDate != null
      ? summaryForDate(streams?.currentIntervalStreams, selectedDate)
      : {
          current: streams?.currentIntervalStreamsSum,
          previous: streams?.previousIntervalStreamsSum,
          changePercentage: streams?.changePercentage,
        }

  const selectedDateStreamsPerDsp =
    dsp === 'all'
      ? streamingDsps.map((dsp) => {
          const [streams] = useEntityStreams(selectedInterval, dsp)

          return {
            dsp,
            streams: selectedDate
              ? streams?.currentIntervalStreams.find(
                  ({ date }) => date === selectedDate
                )?.data ?? 0
              : streams?.currentIntervalStreamsSum ?? 0,
          }
        })
      : null

  return streams ? (
    <DaySummary
      currentValue={streamsSummary.current}
      previousValue={streamsSummary.previous}
      currentValuePerDsp={selectedDateStreamsPerDsp}
      totalLabel={totalLabel}
      changeLabel={changeLabel}
      gainLossLabel={gainLossLabel}
    />
  ) : null
}

export const EntityStreamsGraphScreenContent: React.FC<{
  screenName: string
  screenTitle?: string
  title: string
  headerImage: React.ReactNode
  dsp: Dsp | 'all'
  countryCode: string
  selectedTimeInterval: TimeInterval
  selectTimeInterval: (timeInterval: TimeInterval) => void
  onSelectTimeInterval: (timeInterval: TimeInterval) => void
  getSummaryData: (interval: Interval, dsp: Dsp | 'all') => IntervalSummary[]
  error: NetworkError | null
  showToast: boolean
  navigation: NavigationProp<ScreenNames>
  retry: () => void
  refreshing: boolean
  onPressMarketSelectorButton?: () => void
  totalLabel: string
  gainLossLabel: string
  changeLabel: string
  contextMenuItems?: ContextMenuItem[]
}> = ({
  screenName,
  screenTitle,
  title,
  headerImage,
  dsp,
  countryCode,
  selectedTimeInterval,
  selectTimeInterval,
  onSelectTimeInterval,
  getSummaryData,
  error,
  showToast,
  navigation,
  retry,
  refreshing,
  onPressMarketSelectorButton,
  totalLabel,
  gainLossLabel,
  changeLabel,
  contextMenuItems,
}) => {
  const renderSelectedDateSummary = (
    selectedInterval: Interval,
    selectedTimeInterval: TimeInterval,
    selectedBar: number | null
  ) => (
    <SelectedDateSummary
      selectedInterval={selectedInterval}
      selectedTimeInterval={selectedTimeInterval}
      selectedBar={selectedBar}
      dsp={dsp}
      useEntityStreams={getSummaryData}
      totalLabel={totalLabel}
      gainLossLabel={gainLossLabel}
      changeLabel={changeLabel}
    />
  )

  return (
    <GraphScreenContent
      screenName={screenName}
      screenTitle={screenTitle}
      title={title}
      headerImage={headerImage}
      dsp={dsp}
      countryCode={countryCode}
      selectedTimeInterval={selectedTimeInterval}
      selectTimeInterval={selectTimeInterval}
      onSelectTimeInterval={onSelectTimeInterval}
      error={error}
      showToast={showToast}
      navigation={navigation}
      retry={retry}
      refreshing={refreshing}
      onPressMarketSelectorButton={onPressMarketSelectorButton}
      renderSelectedDateSummary={renderSelectedDateSummary}
      renderGraph={(
        selectedBar: number | null,
        selectBar: (index: number | null) => void,
        selectedInterval: Interval,
        _selectedTimeInterval: TimeInterval,
        _selectTimeInterval: (timeInterval: TimeInterval) => void,
        setScrollEnabled: (enabled: boolean) => void
      ) => {
        const summaries = getSummaryData(selectedInterval, dsp)

        const plots: PlotConfig<number | null>[] =
          summaries?.map((summary) => ({
            type: 'line',
            data: summary.currentIntervalStreams.map((x) => x.data),
            axisSide: 'right',
            color: colors.offWhite,
            lineStrokeColor: DspColors[summary.dsp ?? 'all'],
            lineStrokeWidth: 2.5,
          })) ?? []

        return (
          <View style={{ flex: 1 }}>
            {summaries != null && summaries?.length > 0 ? (
              <TrackDateDataFigure
                plots={plots}
                axisConfig={{ right: { bounds: { min: 0 } } }}
                selectBar={selectBar}
                selectedBar={selectedBar}
                selectedInterval={selectedInterval}
                onHoverBar={() => setScrollEnabled(false)}
                onHoverBarEnd={() => setScrollEnabled(true)}
              />
            ) : (
              <CenteredActivityIndicator />
            )}
          </View>
        )
      }}
      contextMenuItems={contextMenuItems}
    />
  )
}
