import React from 'react'
import { Select, Spin } from 'antd'
import { throttle } from 'lodash'
import { createRequest } from 'toss.request'

const defaultDataMapper = data => data

export default class LazySelect extends React.Component {
  static defaultProps = {
    allowClear: true,
    showSearch: true,
    showAll: false,
    allOptionValue: '',
    allOptionLabel: '全部',
    pageSize: 10,
    pageNumFieldName: 'pageNum',
    keywordFieldName: 'keyword',
    defaultOptions: [],
    dataMapper: defaultDataMapper,
  }

  constructor(props) {
    super(props)
    this.requestData = throttle(this.requestData, 600)
    this.state = {
      defaultValue: '',
    }
  }

  state = {
    pageNum: 1,
    options: [],
    value: undefined,
    hasNextPage: true,
    requesting: false,
  }

  lastRequestId = 0
  componentDidMount() {
    this.setState({
      defaultValue: this.props.defaultValue,
    })
  }
  requestData(keyword, isLoadMore) {
    this.lastRequestId += 1

    const lastRequestId = this.lastRequestId
    const { options, pageNum, hasNextPage } = this.state
    const { pageSize, dataMapper, serviceName, pageNumFieldName, keywordFieldName, requestParams: extRequestParams } = this.props

    const requestParams = {
      pageSize,
      [keywordFieldName]: keyword,
      ...extRequestParams,
    }
    let requestFn = null

    if (!serviceName) {
      throw TypeError('未指定有效的serviceName，无法发起请求')
    }

    if (isLoadMore) {
      if (!hasNextPage) {
        return false
      }
      requestParams[pageNumFieldName] = pageNum
      this.setState({ requesting: true })
    } else {
      requestParams[pageNumFieldName] = 1
      this.setState({
        options: [],
        keyword: keyword,
        pageNum: 1,
        hasNextPage: true,
        requesting: true,
      })
    }

    createRequest(serviceName, requestParams)
      .then(res => {
        if (lastRequestId !== this.lastRequestId) {
          return
        }
        const { code, data } = res
        const { hasNextPage = true } = data
        const newOptions = dataMapper(data.list)
        if (isLoadMore) {
          this.setState({
            options: [...options, ...newOptions],
            pageNum: newOptions.length > 0 ? requestParams[pageNumFieldName] + 1 : requestParams[pageNumFieldName],
            hasNextPage: hasNextPage,
            requesting: false,
          })
        } else {
          this.setState({
            options: newOptions,
            pageNum: newOptions.length > 0 ? requestParams[pageNumFieldName] + 1 : requestParams[pageNumFieldName],
            hasNextPage: hasNextPage,
            requesting: false,
          })
        }
      })
      .catch(error => {
        console.warn(error)
        this.setState({
          requesting: false,
        })
      })
  }

  handleDropdownExpand = () => {
    if (!this.state.options || this.state.options.length === 0) {
      this.requestData('', false)
    }
  }

  requestDataForNewKeyword = keyword => {
    this.requestData(keyword, false)
  }

  requestDataForMorePage = event => {
    if (event.target.scrollTop + event.target.offsetHeight === event.target.scrollHeight) {
      this.requestData(this.state.keyword, true)
    }
  }

  handleChange = value => {
    !value && this.state.keyword && this.requestDataForNewKeyword('')
    this.props.onChange && this.props.onChange(value)
  }

  render() {
    const {
      className,
      disabled,
      showSearch,
      value,
      showAll,
      allOptionValue,
      allOptionLabel,
      allowClear,
      placeholder,
      selectorProps,
      defaultOptions,
    } = this.props
    const { requesting, options = [] } = this.state
    const renderedOptions = options
      .concat(defaultOptions)
      .filter((item, index, array) => array.findIndex(subItem => subItem.value === item.value) === index)

    return (
      <Select
        value={value}
        disabled={disabled}
        filterOption={false}
        allowClear={allowClear}
        showSearch={showSearch}
        placeholder={placeholder}
        onChange={this.handleChange}
        onSearch={this.requestDataForNewKeyword}
        onPopupScroll={this.requestDataForMorePage}
        onDropdownVisibleChange={this.handleDropdownExpand}
        className={`lz-component-lazy-selector ${className}`}
        notFoundContent={requesting ? <Spin size="small" /> : null}
        {...selectorProps}>
        {showAll ? <Select.Option value={allOptionValue}>{allOptionLabel}</Select.Option> : null}
        {renderedOptions.map(item => (
          <Select.Option value={item.value} key={item.value}>
            {item.label}
          </Select.Option>
        ))}
      </Select>
    )
  }
}
