import React, { useState } from 'react'
import {
  LayoutChangeEvent,
  StyleProp,
  Text,
  View,
  ViewStyle,
} from 'react-native'
import { ScrollView, TouchableOpacity } from 'react-native-gesture-handler'
import { colorsV2 } from '../Colors'
import { Dsp, streamingDsps } from '../Consts'
import { useComponentLayout } from '../hooks/useComponentLayout'
import { Strings } from '../i18n'
import { periodToPeriodChangePercentage } from '../streams'
import { TextStylesV2 } from '../Styles'
import {
  CurrentAndPreviousByDate,
  TrackWithStreamsByDspAndDate,
} from '../types/types'
import { formatCountShort } from '../util'
import { DiffNumber } from './DiffNumber'
import { DspStreams } from './DspStreams'
import * as d3Scale from 'd3-scale'
import * as d3Array from 'd3-array'
import _ from 'lodash'

function trackDspData(
  track: TrackWithStreamsByDspAndDate,
  dsp: Dsp | 'all'
): CurrentAndPreviousByDate | undefined {
  return track.data.find((x) => x.dsp === dsp)
}

/**
 * A single track in the comparison
 */
const TrackComparisonTrack: React.FC<{
  track: TrackWithStreamsByDspAndDate
  onBarLayout?: (e: LayoutChangeEvent) => void
  onPress: () => void
  highlighted: boolean
  scale?: (number) => number
  style?: StyleProp<ViewStyle>
}> = ({ track, onBarLayout, onPress, highlighted, scale, style }) => {
  const streams = trackDspData(track, 'all')?.currentPeriod ?? 0
  const width = scale != null ? scale(streams) : null
  return (
    <TouchableOpacity
      style={[
        {
          flexDirection: 'row',
          alignItems: 'center',
          flex: 1,
        },
        style,
      ]}
      onPress={onPress}
    >
      <View
        style={[
          {
            height: 7,
            backgroundColor: highlighted
              ? colorsV2.platform.spotify
              : colorsV2.metals.metal1,
            marginVertical: 7,
            marginRight: 8,
            borderTopRightRadius: 1,
            borderBottomRightRadius: 1,
          },
          width != null ? { width } : { flex: 1 },
        ]}
        onLayout={onBarLayout}
      />
      <View style={{ flexShrink: 1, flexGrow: 0 }}>
        <Text
          style={[TextStylesV2.small, { color: colorsV2.white }]}
          numberOfLines={1}
          ellipsizeMode={'tail'}
        >
          {track.item.name}
        </Text>
      </View>
    </TouchableOpacity>
  )
}

/**
 * Summary for a track
 */
const TrackPerformanceSummary: React.FC<{
  track: TrackWithStreamsByDspAndDate | null
}> = ({ track }) => {
  const all = track != null ? trackDspData(track, 'all') : null
  return (
    <View
      style={{
        height: 87,
      }}
    >
      {track != null ? (
        <>
          <View
            style={{ flexDirection: 'row', justifyContent: 'space-between' }}
          >
            <View>
              <Text
                style={{
                  ...TextStylesV2.tiny,
                  ...{ color: colorsV2.metals.metal0 },
                }}
              >
                {Strings.Shared.Total}
              </Text>
              <Text style={[TextStylesV2.bodyBold, { color: colorsV2.white }]}>
                {formatCountShort(all?.currentPeriod ?? 0)}
              </Text>
            </View>
            <View>
              <Text
                style={{
                  ...TextStylesV2.tiny,
                  ...{ color: colorsV2.metals.metal0 },
                }}
              >
                {Strings.Shared.Change}
              </Text>
              <DiffNumber
                value={Math.round(
                  periodToPeriodChangePercentage(
                    all ?? {
                      currentPeriodByDay: undefined,
                      previousPeriodByDay: undefined,
                    }
                  ) ?? 0
                )}
                size="large"
                type="percentage"
              />
            </View>
          </View>
          <View
            style={{ flexDirection: 'row', justifyContent: 'space-between' }}
          >
            {streamingDsps.map((dsp) => (
              <DspStreams
                key={dsp}
                dsp={dsp}
                streams={trackDspData(track, dsp)?.currentPeriod ?? 0}
                gap={8}
              />
            ))}
          </View>
        </>
      ) : (
        <Text
          style={{
            ...TextStylesV2.tiny,
            ...{ color: colorsV2.metals.metal0 },
          }}
        >
          {Strings.TrackComparison.TapBarChartToSeeTheTrackDetails}
        </Text>
      )}
    </View>
  )
}

/**
 * A set of bars representing tracks
 *
 * The width of the bar representing the top track is first measured, then all other bars are sized relative to that
 */
export const TrackComparison: React.FC<{
  tracks: TrackWithStreamsByDspAndDate[]
}> = ({ tracks }) => {
  // Number of streams for the track with most streams
  const maxTrackStreams = Math.max(
    ...tracks.map((track) => trackDspData(track, 'all')?.currentPeriod ?? 0)
  )

  const sortedTracks = tracks.sort(
    (a, b) =>
      (trackDspData(b, 'all')?.currentPeriod ?? 0) -
      (trackDspData(a, 'all')?.currentPeriod ?? 0)
  )

  const [onMaxBarLayout, maxBarLayout] = useComponentLayout()
  const [onContainerLayout, containerLayout] = useComponentLayout()
  const [selectedTrackISRC, selectTrackISRC] = useState<string | null>(null)
  const toggleSelectedTrackISRC = (isrc: string) =>
    selectTrackISRC(selectedTrackISRC === isrc ? null : isrc)
  const selectedTrack =
    tracks.find((track) => track.item.isrc === selectedTrackISRC) ?? null

  const numTicks = 7
  const range = [0, maxBarLayout?.width]
  const domain = [0, maxTrackStreams]
  const scale =
    maxBarLayout != null
      ? d3Scale.scaleLinear(domain, range).nice(numTicks)
      : null

  const margin = 20
  // Number of streams (`margin` pixels away) from the right edge of the view
  const maxViewStreams =
    containerLayout?.width != null && scale != null
      ? scale.invert(containerLayout.width - margin)
      : null

  const ticks = d3Array.ticks(domain[0], maxViewStreams, numTicks)

  return (
    <View style={{ flex: 1 }} onLayout={onContainerLayout}>
      <TrackPerformanceSummary track={selectedTrack} />
      <View style={{ flex: 1 }}>
        <View
          style={{
            position: 'absolute',
            left: 0,
            right: 0,
            top: 0,
            bottom: 0,
          }}
        >
          {ticks != null &&
            scale != null &&
            ticks
              .slice(1) //Don't draw a line at 0
              .map((tick, i) => (
                <View
                  key={i}
                  style={{
                    position: 'absolute',
                    width: 1,
                    height: '100%',
                    backgroundColor: colorsV2.metals.metal1,
                    left: scale(tick),
                  }}
                />
              ))}
        </View>
        <ScrollView>
          <View style={maxBarLayout == null ? { opacity: 0 } : null}>
            {/* Invisible view, used for layout width measurement only */}
            <TrackComparisonTrack
              key={sortedTracks[0].item.isrc}
              track={sortedTracks[0]}
              onBarLayout={onMaxBarLayout}
              onPress={() => toggleSelectedTrackISRC(sortedTracks[0].item.isrc)}
              highlighted={
                selectedTrackISRC === null ||
                selectedTrackISRC === sortedTracks[0].item.isrc
              }
              style={{ position: 'absolute', opacity: 0 }}
            />
            {sortedTracks.map((track, i) => (
              <TrackComparisonTrack
                key={track.item.isrc}
                track={track}
                onPress={() => toggleSelectedTrackISRC(track.item.isrc)}
                highlighted={
                  selectedTrackISRC === null ||
                  selectedTrackISRC === track.item.isrc
                }
                scale={scale}
              />
            ))}
          </View>
        </ScrollView>
      </View>
      <View
        style={{
          height: 16,
        }}
      >
        {ticks != null &&
          scale != null &&
          ticks.map((tick, i) => (
            <Text
              key={i}
              style={[
                TextStylesV2.small,
                {
                  position: 'absolute',
                  color: colorsV2.offWhite,
                },
                { left: scale(tick) },
              ]}
            >
              {formatCountShort(tick)}
            </Text>
          ))}
      </View>
    </View>
  )
}
