import React, { memo, useEffect, useState, useCallback, useMemo } from 'react'

import { ExposerEvent, Value } from '@aptpod/data-viz-visual-parts-sdk'

import { INIT_TIME_SELECTED_RANGE, INIT_VALUES } from './constant'
import { TimeSeriesText } from './component'
import { arraySearchIndexLe, arraySearchIndexGe } from './utils'

type Props = {
  comm: ExposerEvent
}

//--------------------------------------------------------------
//
// 時間範囲で取得する計測データを抽出する際に使用する型を定義、定数を定義します
//
//--------------------------------------------------------------
/**
 * Valueの型をdataフィールドのみで再定義
 * = { data: [] }
 */
type UsedValue = Pick<Value, 'data'>

/**
 * Value.dataの配列要素をにTimestamのみで再定義
 * = { t: number }
 */
type UsedValueDataTimestamp = Pick<UsedValue['data'][0], 't'>

/**
 * データポイント配列のデフォルト
 */
const DEFAULT_VALUE: UsedValue = { data: [] }

/**
 * data-viz-visual-parts-sdk から取得したデータを TimeSeriesText Component に必要なPropsに連携します。
 */
export const TimeSerieseTextContainer: React.FC<Props> = memo((props) => {
  // TimeSeriesText を表示するためのStateを定義します。
  const [timeSelectedRange, setTimeSelectedRange] = useState(
    INIT_TIME_SELECTED_RANGE,
  )
  const [values, setValues] = useState(INIT_VALUES)

  // ExposerEventのイベントハンドラを定義します。
  // イベント初期設定完了後、loadedイベントを Data Visualizerに通知します。
  useEffect(() => {
    // Data Visualizer で選択されている時間範囲を取得します。
    props.comm.playbackTimeSelectedRange.on(setTimeSelectedRange)
    // Data Visualizer のパネルにバインドされているビジュアルパーツの拡張設定情報を取得します。
    props.comm.values.on(setValues)
    // Data Visualizer に、ビジュアルパーツのイベント取得初期設定が完了したことを通知します。
    props.comm.loaded.emit()
  }, [props.comm])

  //--------------------------------------------------------------
  //
  // 時間範囲で取得する計測データを抽出します。
  //
  //--------------------------------------------------------------
  const timeCompare = useCallback(
    (a: UsedValueDataTimestamp, b: UsedValueDataTimestamp) => a.t - b.t,
    [],
  )

  // 先頭にバインドされている計測データ全てを取得します。
  // 見つからない場合は、DEFAULT_VALUEを使用します。
  const valueData = (values[0] ?? DEFAULT_VALUE).data

  // 時間範囲で計測データを抽出します。
  // 時間範囲内に計測データが見つからない場合は、DEFAULT_VALUEのdataを使用します。
  const gotValues = useMemo(() => {
    // 始点を含む直近の未来の時刻に該当する配列Indexを検索します。
    const startIndex = arraySearchIndexGe(
      valueData as UsedValueDataTimestamp[],
      { t: timeSelectedRange.start },
      timeCompare,
    )

    // 終点を含む直近の過去の時刻に該当する配列Indexを検索します。
    const endIndex = arraySearchIndexLe(
      valueData as UsedValueDataTimestamp[],
      { t: timeSelectedRange.end },
      timeCompare,
    )

    // 始点、終点の検索でいずれか見つからない場合は、DEFAULT_VALUEのdataを使用します。
    if (startIndex < 0 || endIndex < 0) {
      return DEFAULT_VALUE.data
    }

    // 検索で見つかった範囲の計測データを抽出します。
    return valueData.slice(startIndex, endIndex + 1)
  }, [timeCompare, timeSelectedRange.end, timeSelectedRange.start, valueData])

  //--------------------------------------------------------------
  //
  // 時間範囲で抽出した計測データを表示します。
  //
  //--------------------------------------------------------------
  return <TimeSeriesText values={gotValues} />
})
