/*
 * Copyright (c) 2018-present, Revolut LTD.
 *
 * This source code is licensed under the Apache 2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */
import * as React from 'react'
import makeControllable from 'make-controllable'
import { TabsWrap, Pointer, TabItem, HiddenValue } from './styles'
export type RenderItemDefaultProps = {
  item?: {
    id?: string
    title?: string
    titleFunc?: (...args: any[]) => any
    disabled?: boolean
  }
  state?: object
  handleChange?: (...args: any[]) => any
  index?: number
  valueIndex?: number
}
const renderItemDefault: React.SFC<RenderItemDefaultProps> = ({
  item = {},
  state,
  handleChange,
  index,
  valueIndex,
}) => {
  const content = item.titleFunc ? item.titleFunc(item, state) : item.title
  return (
    <TabItem
      active={index === valueIndex}
      key={item.id}
      onClick={() => handleChange(item.id)}
    >
      <div>{content}</div>
      <HiddenValue>{content}</HiddenValue>
    </TabItem>
  )
}
const renderListDefault = ({ list = [], renderItem, state, ...restProps }) => {
  const valueIndex = list.findIndex(item => item.id === state.value)
  return list.map((item, index) =>
    renderItem({
      ...restProps,
      item,
      state,
      index,
      valueIndex,
    }),
  )
}
const filterDisabled = (list = []) => list.filter(item => !item.disabled)
export type TabsProps = {
  items?: {
    id?: string
    title?: string
    titleFunc?: (...args: any[]) => any
    disabled?: boolean
  }[]
  value?: string
  renderItem?: (...args: any[]) => any
  renderList?: (...args: any[]) => any
  onChange?: (...args: any[]) => any
  pointerPosition?: 'top' | 'bottom'
  showPointer?: boolean
}

type TabsState = {
  pointer: { left: string; width: string }
  value: any
}

export class Tabs extends React.Component<TabsProps, TabsState> {
  static defaultProps = {
    renderItem: renderItemDefault,
    renderList: renderListDefault,
    items: [],
    pointerPosition: 'bottom',
    showPointer: true,
  }

  state = {
    pointer: {
      left: '',
      width: '',
    },
    value: this.props.value,
  }

  navContent
  pointerTimeout
  componentDidMount() {
    const { showPointer } = this.props
    if (showPointer) {
      const { value } = this.state
      // @ts-ignore
      const items = filterDisabled(this.props.items)
      this.updatePointer(items.findIndex(item => item.id === value))
    }
  }

  static getDerivedStateFromProps(props, state) {
    return makeControllable(props, state, 'value')
  }

  componentWillUnmount() {
    clearTimeout(this.pointerTimeout)
  }

  handleChange = value => {
    const { onChange, showPointer } = this.props
    const items = filterDisabled(this.props.items)
    if (onChange) {
      onChange(value)
    }
    if (showPointer) {
      this.updatePointer(items.findIndex(item => item.id === value))
    }
    this.setState({ value })
  }

  // tslint:disable-next-line
  componentDidUpdate(nextProps) {
    const { value, showPointer } = nextProps
    const items = filterDisabled(this.props.items)
    if (showPointer) {
      this.updatePointer(items.findIndex(item => item.id === value))
    }
  }

  updatePointer(index) {
    clearTimeout(this.pointerTimeout)
    this.pointerTimeout = setTimeout(() => {
      if (this.navContent && this.navContent.children.length && index >= 0) {
        const startPoint = this.navContent.getBoundingClientRect().left
        const label = this.navContent.children[index].getBoundingClientRect()
        // TODO: replace by css transition!
        this.setState({
          pointer: {
            left: `${label.left - startPoint}px`,
            width: `${label.width}px`,
          },
        })
      }
    }, 20)
  }
  render() {
    const { renderList, pointerPosition, showPointer } = this.props
    const { pointer } = this.state
    const items = filterDisabled(this.props.items)
    return (
      <TabsWrap pointerPosition={pointerPosition}>
        <div
          ref={element => {
            this.navContent = element
          }}
        >
          {renderList({
            ...this.props,
            state: this.state,
            handleChange: this.handleChange,
            list: items,
          })}
        </div>
        <div>{showPointer && <Pointer style={pointer} />}</div>
      </TabsWrap>
    )
  }
}
