import React, {Component} from 'react'
import styled from 'styled-components'
import classNames from 'classnames/bind'
import {
  MdSettings, MdCheckBox, MdCheckBoxOutlineBlank, MdKeyboardArrowUp, MdKeyboardArrowDown, MdAddCircle,
  MdLock, MdWarning,
} from 'react-icons/lib/md'
import Button from 'components/utils/button'
import TimeAgo from 'components/utils/time_ago'
import MoreButton from './more_button'
import FileDropzone from 'components/file_dropzone'
import CodeEditor from 'components/code_editor'
import store from 'common/store'
import event_system from 'common/event_system'
import auto_bind from 'common/auto_bind'
import {color, link} from 'common/styles'
import {array_contains, empty_array, download_file} from 'common/utilities'
import {action_update_field, action_update_field_template} from 'common/fields'
import {alert_warning} from 'actions/display'

const cx = classNames.bind(require('../styles/fields_table.scss'))
const value_width = 300
const icon_width = 40

class FieldsTable extends Component {
  constructor(props) {
    super(props)
    this.state = {
      width: 300,
    }
    this.update_width = this.update_width.bind(this)
    this.render_option = this.render_option.bind(this)
    this.render_field = this.render_field.bind(this)
  }

  componentDidMount() {
    this.update_width()
    this.cancel_update_width = event_system.register("window_resize", this.update_width)
  }

  componentWillUnmount() {
    this.cancel_update_width()
  }

  update_width() {
    let width = $(this.fields_table).width()
    if (width != this.state.width) {
      this.setState({width})
    }
  }

  render_option({name}, index) {
    return (
      <div key={index} className={cx('fields-table__header-options-option')}>
        {name}
      </div>
    )
  }

  render_field(field) {
    return (
      <Field {...field} field={field} width={this.state.width} key={field.id} options={this.props.options} />
    )
  }

  render() {
    return (
      <div ref={(fields_table) => this.fields_table = fields_table} className={cx('fields-table')}>
        <div className={cx('fields-table__header')}>
          <div className={cx('fields-table__header-name')}>
            Nom du champ
          </div>
          <div className={cx('fields-table__header-options')}>
            {this.props.options.map(this.render_option)}
          </div>
        </div>
        {this.props.fields.length ? (
          <div className={cx('fields-table__fields')}>
            {this.props.fields.map(this.render_field)}
          </div>
        ) : (
          <div className={cx('fields-table__fields-placeholder')}>
            Il n'y a aucun champ.
          </div>
        )}
      </div>
    )
  }
}

class Field extends Component {
  constructor(props) {
    super(props)
    this.state = {
      open: false,
      editing: false,
    }
    auto_bind(this)
  }

  toggle_editing() {
    this.setState(({editing}) => ({editing: !editing}))
  }

  toggle_open() {
    if (!this.props.locked && this.props.editable) {
      this.setState(({open}) => ({open: !open}))
    }
  }

  toggle_option(toggle) {
    if (this.props.locked) {
      return null
    } else {
      return (event) => {
        event.stopPropagation()
        if (this.props.editable) {
          action_update_field(toggle(this.props.field))
        } else {
          this.props.update(toggle(this.props.field))
        }
      }
    }
  }

  on_change_name(name) {
    this.props.update({name})
    this.toggle_editing()
  }

  update_code(code) {
    this.props.update({code})
  }

  stop_recycling() {
    this.props.update({recycled: false})
  }

  create_value() {
    this.props.create_value()
  }

  update_template([template]) {
    const {id} = this.props
    action_update_field_template(id, template)
  }

  download_template() {
    const {template: {url, name}} = this.props
    download_file(url, name)
  }

  render_option({get, toggle}, index) {
    return (
      <div key={index} onClick={this.toggle_option(toggle)} className={cx('fields-table__field-header-options-option')}>
        {get(this.props.field) ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
      </div>
    )
  }

  render_value(value) {
    let available_width = this.props.width - 2 * icon_width - 2
    let columns_number = Math.floor(available_width / value_width) || 1
    let width = available_width / columns_number
    let {id} = value
    return (
      <Value {...value} width={width} key={id} field_name={this.props.name} />
    )
  }

  render_details() {
    const {category, template, values, code} = this.props
    switch (category) {
      case "exclusive":
      case "non_exclusive":
        return [
          ...values.map(this.render_value),
          <Button
            key={'new-value'}
            discreet
            icon={MdAddCircle}
            className={cx('fields-table__field-details-new-value')}
            onClick={this.create_value}
            >
            Nouvelle Valeur
          </Button>
        ]
      case "comment":
        return (
          <div className={cx('fields-table__field-details-simple')}>
            Champ de commentaire
          </div>
        )
      case "file":
        return (
          <div className={cx('fields-table__field-details-simple')}>
            Document
          </div>
        )
      case "template":
        return (
          <div className={cx('fields-table__field-details-simple', 'fields-table__field-details-simple_template')}>
            {template.url ? (
              <DocumentInformation>
                Mis à jour&nbsp;<TimeAgo>{template.updated_at}</TimeAgo>
                <Download onClick={this.download_template}>Voir</Download>
              </DocumentInformation>
            ) : null}
            <FileDropzone on_files_drop={this.update_template}>
              Modifier le modèle de document
            </FileDropzone>
          </div>
        )
      case "computed":
        return (
          <div className={cx('fields-table__field-details-simple')}>
            <CodeEditor
              value={code}
              on_change={this.update_code}
            />
          </div>
        )
      default:
        return <span style={{color: 'pink', padding: '8px 0'}}>{category}</span>
    }
  }

  render() {
    let {open, editing} = this.state
    let {
      editable, locked, for_entity, recycled, options, name, category, values, template, remove,
      show_associated_values,
    } = this.props
    let error_message = ""
    switch (category) {
      case 'exclusive':
      case 'non_exclusive':
        if (empty_array(values)) {
          error_message = "Ce champ n'a pas de valeur."
        }
        break
      case 'template':
        if (!template.url) {
          error_message = "Le fichier modèle n'a pas été téléchargé."
        }
        break
    }
    return (
      <div
        className={cx('fields-table__field', {
          'fields-table__field_open': open,
          'fields-table__field_locked': locked,
          'fields-table__field_unlocked': !locked,
          'fields-table__field_editable': editable,
        })}
        >
        <div onClick={this.toggle_open} className={cx('fields-table__field-header')}>
          {editing ? (
            <Input value={name} on_change={this.on_change_name} auto_focus />
          ) : (
            <div className={cx('fields-table__field-header-name')}>
              <div className={cx('fields-table__field-header-name-label')}>
                {name}
              </div>
              {editable && !locked ? (
                <MoreButton
                  start_edit={this.toggle_editing}
                  on_delete={recycled ? null : remove}
                  stop_recycling={recycled ? this.stop_recycling : null}
                  show_associated_values={show_associated_values}
                  />
              ) : null}
              {error_message ? (
                <div className={cx('fields-table__field-header-name-warning')}>
                  <MdWarning />
                  <span className={cx('fields-table__field-header-name-warning-label')}>
                    {error_message}
                  </span>
                </div>
              ) : null}
            </div>
          )}
          <div className={cx('fields-table__field-header-options')}>
            {options.map(this.render_option)}
          </div>
          <div className={cx('fields-table__field-header-toggle-open')}>
            {locked ? (
              <MdLock />
            ) : (editable ? (
              open ? <MdKeyboardArrowUp /> : <MdKeyboardArrowDown />
            ) : null)}
          </div>
        </div>
        {open ? (
          <div className={cx('fields-table__field-details')}>
            {this.render_details()}
          </div>
        ) : null}
      </div>
    )
  }
}

Field.defaultProps = {editable: true, locked: false}

class Value extends Component {
  constructor(props) {
    super(props)
    auto_bind(this)
  }

  render() {
    const {options, name, width, show_associated_values} = this.props
    return (
      <div className={cx('fields-table__value')} style={{width}}>
        <div onClick={show_associated_values} className={cx('fields-table__value-label', {'fields-table__value-label_empty': !name})}>
          {name || "Valeur sans nom"}
        </div>
      </div>
    )
  }
}

class Input extends Component {
  constructor(props) {
    super(props)
    this.state = {
      value: props.value,
    }
    auto_bind(this)
  }

  componentWillReceiveProps({value}) {
    if (value != this.props.value) {
      this.setState({value})
    }
  }

  componentDidMount() {
    if (this.props.auto_focus) {
      this.input.focus()
    }
  }

  onChange({target: {value}}) {
    if (array_contains([',', ';'], value.slice(-1))) {
      store.dispatch(alert_warning(`Le caractère '${value.slice(-1)}' n'est pas autorisé dans le nom d'un champ.`))
      value = value.slice(0, -1)
    }
    this.setState({value})
  }

  onBlur() {
    this.props.on_change(this.state.value.trim())
  }

  render() {
    return (
      <input
        ref={(input) => this.input = input}
        type="text"
        placeholder="Nom"
        className={cx('fields-table__input')}
        value={this.state.value || ""}
        onChange={this.onChange}
        onBlur={this.onBlur}
        />
    )
  }
}

FieldsTable.defaultProps = {
  fields: [],
  options: [],
}

export default FieldsTable

const DocumentInformation = styled.div`
  padding: 5px 0;
  display: flex;
`
const Download = styled.div`
  ${link}
  color: ${color('black', 'bright')};
  text-decoration: underline;
  padding: 0 5px;
`
