import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'dva'
import { Table, Input, InputNumber, Form } from 'antd'
import { isEqual, cloneDeep } from 'lodash'
import classNames from 'classnames'
import styles from './index.css'

class EditableCell extends Component {
  constructor (props) {
    super(props)
    this.state = {
      editValue: props.data?.value,
      onEdit: false,
      help: undefined,
      validateStatus: undefined
    }
  }

  handleEditSave = () => {
    const { rule, errorMsg } = this.props.data
    if (rule && !(new RegExp(rule).test(this.state.editValue))) {
      this.setState({
        help: errorMsg || '校验失败',
        validateStatus: 'error'
      })
      return
    }
    this.setState({
      help: undefined,
      validateStatus: undefined
    }, () => {
      this.toggleEdit()
      const { onChange } = this.props
      onChange instanceof Function && onChange(this.state.editValue)
    })
  }

  handleEditChange = (evt) => {
    const { controlType } = this.props.data
    this.setState({ editValue: controlType === 7 ? evt : evt.target?.value })
  }

  handleKeyDown = (evt) => {
    // 当前 antd 版本（3.19.8）InputNumber 的 onPressEnter 事件没实现，所以通过 onKeyDown 监听 Enter 事件
    if ((evt.keyCode === 13 || evt.which === 13)) {
      this.handleEditSave()
    }
  }

  toggleEdit = () => {
    this.setState({ onEdit: !this.state.onEdit })
  }

  render () {
    const { value, disabled, controlType, backgroundColor = 'unset', fontColor: color = 'unset' } = this.props.data
    const { onEdit, help, validateStatus } = this.state
    if (onEdit && !disabled) {
      const formItemProps = { help, validateStatus, style: { marginBottom: 0 } }
      if (controlType === 7) {
        return (
          <Form>
            <Form.Item {...formItemProps}>
              <InputNumber
                autoFocus
                defaultValue={value}
                formatter={val => isNaN(val) ? value : val}
                onChange={this.handleEditChange}
                onKeyDown={this.handleKeyDown}
                onBlur={this.handleEditSave}
                className={styles['editable-cell__input']}
              />
            </Form.Item>
          </Form>
        )
      }
      return (
        <Form>
          <Form.Item {...formItemProps}>
            <Input
              autoFocus
              defaultValue={value}
              onChange={this.handleEditChange}
              onPressEnter={this.handleEditSave}
              onBlur={this.handleEditSave}
              className={styles['editable-cell__input']}
            />
          </Form.Item>
        </Form>
      )
    }
    const cellClass = classNames(styles['editable-cell__default'], { [styles['editable-cell__disabled']]: disabled })
    const style = { backgroundColor, color }
    return <div onClick={() => { !disabled && this.toggleEdit() }} className={cellClass} style={style}>{value}</div>
  }
}

class EditableTable extends Component {
  constructor (props) {
    super(props)
    const { data, columns } = props
    const copyData = this.generateData(data)
    const copyColumns = cloneDeep(columns)
    this.generateColumns(copyColumns)
    this.state = {
      data: copyData,
      columns: copyColumns
    }
  }

  UNSAFE_componentWillReceiveProps (nextProps) {
    const { data, columns } = nextProps
    const { data: currData, columns: currColumns } = this.props
    if (!isEqual(data, currData) || !isEqual(columns, currColumns)) {
      const copyData = this.generateData(data)
      const copyColumns = cloneDeep(columns)
      this.generateColumns(copyColumns)
      this.setState({
        data: copyData,
        columns: copyColumns
      })
    }
  }

  /**
   * 生成提交给后端的数据
   * @param {*} data 
   * @returns 
   */
  generatePostData = (data) => {
    return data.map(item => {
      const result = {}
      Object.keys(item).forEach(key => {
        if (typeof item[key] === 'object') {
          result[key] = item[key].value
        } else {
          result[key] = item[key]
        }
      })
      return result
    })
  }

  handleEditableCellChange = (val, dataIndex, index) => {
    const { data } = this.state
    const initData = data[index][dataIndex]
    if (initData && !isEqual(val, initData.value)) {
      initData.value = val
      this.forceUpdate()
      this.props.onEdit instanceof Function && this.props.onEdit(this.generatePostData(data))
    }
  }

  generateData = (data) => {
    return cloneDeep(data).map(item => {
      const source = {}
      item.forEach(field => {
        const { fieldName, ...rest } = field
        source[fieldName] = { ...rest }
      })
      return source
    })
  }

  generateColumns = (columns) => {
    if (Array.isArray(columns) && columns.length) {
      columns.forEach(item => {
        const { dataIndex, children } = item
        if (Array.isArray(children) && children.length) {
          this.generateColumns(children)
        } else {
          delete item.children
          item.render = (text, record, index) => {
            const { colSpan, rowSpan } = text
            return {
              children: <EditableCell data={text} onChange={(val) => this.handleEditableCellChange(val, dataIndex, index)} />,
              props: {
                colSpan: colSpan,
                rowSpan: rowSpan
              }
            }
          }
        }
      })
    }
  }

  render () {
    const { rowSelection, style } = this.props
    const { data, columns } = this.state
    return (
      <div className={styles['editable-table__wrap']} style={style}>
        <Table
          bordered
          size='small'
          dataSource={data}
          columns={columns}
          rowSelection={rowSelection}
          pagination={false}
          className={styles['editable-table']}
        />
      </div>
    )
  }
}

EditableTable.propTypes = {
  data: PropTypes.array,
  columns: PropTypes.array,
  rowSelection: PropTypes.object,
  onEdit: PropTypes.func
}

EditableTable.defaultProps = {
  data: [],
  columns: []
}

export default connect(({ login }) => ({ login }))(EditableTable)