import React, {Component} from 'react'
import classNames from 'classnames/bind'
import {MdDone, MdLock, MdCached, MdInsertDriveFile} from 'react-icons/lib/md'
import Dropzone from 'react-dropzone'
import FileDropzone from './file_dropzone'
import TimeAgo from 'components/utils/time_ago'
import ProgressIndicator from './progress_indicator'
import {instant_job_users_fields} from '../common/constants'
import event_system from '../common/event_system'
import auto_bind from '../common/auto_bind'
import {
  property_getter, flatten_array, hash_with_key, property_toggler, empty_set, empty_array, map_hash,
  filter_hash, array_from_hash, download_file,
} from '../common/utilities'
import {update_item, toggle_item_id} from '../reducers/base'

const cx = classNames.bind(require('../styles/user_profile.scss'))

const value_width = 200

function field_is_empty({category, values, comment, file, value}) {
  switch (category) {
    case 'comment':
      return !comment
    case 'non_exclusive':
      return empty_array(values.filter(property_getter('selected')))
    case 'file':
      return !file
    case 'exclusive':
      return !value
  }
}

const add_empty_property_to_field = (field) => ({
  ...field,
  empty: field_is_empty(field),
})

class UserProfile extends Component {
  constructor(props) {
    super(props)
    this.state = {
      ...props.user,
      progress: 0,
    }
    this.render_agency = this.render_agency.bind(this)
  }

  componentDidMount() {
    setTimeout(() => this.setState({progress: 6}), 500)
  }

  render_agency(agency) {
    let fields = agency.fields.map(({id}) => this.agency_fields[id]).filter(Boolean)
    if (!empty_array(fields)) {
      return (
        <Agency
          {...agency}
          fields={fields}
          key={agency.id}
          />
      )
    } else {
      return <div key={agency.id}></div>
    }
  }

  render() {
    let {agencies} = this.props
    let instant_job_fields = instant_job_users_fields.map((field) => ({
      ...field,
      comment: this.state[field.id] || "",
      update: (comment) => {
        this.setState({[field.id]: comment})
        return this.props.update_instant_job_field(field.id, comment)
      },
    })).map(add_empty_property_to_field)
    this.agency_fields = hash_with_key(
      flatten_array(this.props.agencies.map(property_getter('fields')))
      .map(add_empty_property_to_field)
      .filter(({category, values}) => category != 'non_exclusive' || !empty_array(values))
    )
    let progress_fields = [
      ...instant_job_fields,
      ...array_from_hash(this.agency_fields),
    ].filter(({locked}) => !locked)
    return (
      <div className={cx('user-profile')}>
        <div className={cx('user-profile__header')}>
          <div className={cx('user-profile__header-title')}>
            Votre profil
          </div>
          <ProgressIndicator completed={progress_fields.filter(({empty}) => !empty).length} total={progress_fields.length} text={`Complété à ##%`}/>
        </div>
        <Agency
          key={'instantjob'}
          title={"Informations InstantJob"}
          subtitle={"Ces informations seront partagées avec l'ensemble des employeurs avec qui vous avez choisi de travailler."}
          fields={instant_job_fields}
          />
        {agencies.map(this.render_agency)}
      </div>
    )
  }
}

UserProfile.defaultProps = {
  agencies: [],
  user: {},
  update_field: () => new Promise((resolve, reject) => resolve()),
  update_instant_job_field: () => new Promise((resolve, reject) => resolve()),
}

class Agency extends Component {
  constructor(props) {
    super(props)
    this.render_field = this.render_field.bind(this)
  }

  render_field(field) {
    return (
      <Field {...field} key={field.id} />
    )
  }

  render() {
    let {fields, title, name, subtitle} = this.props
    return (
      <div className={cx('user-profile__agency')}>
        <div className={cx('user-profile__agency-header')}>
          <div className={cx('user-profile__agency-header-title')}>
            {name ? `Informations pour ${name}` : title}
          </div>
          <div className={cx('user-profile__agency-header-subtitle')}>
            {subtitle || "Ces informations sont demandées spécifiquement par cet employeur et ne sont pas partagées avec vos autrs employeurs."}
          </div>
        </div>
        {fields.map(this.render_field)}
      </div>
    )
  }
}

export class Field extends Component {
  constructor(props) {
    super(props)
    this.state = {
      synchronisations: {},
      synchronized: true,
    }
    this.idGenerator = 1,
    this.render_indicator = this.render_indicator.bind(this)
    this.render_content = this.render_content.bind(this)
  }

  render_indicator() {
    let state, icon
    let {locked, empty} = this.props
    let synchronized = empty_set(this.state.synchronisations)
    if (locked) {
      state = 'locked'
      icon = <MdLock />
    } else if (!synchronized) {
      state = 'synchronizing'
      icon = <MdCached />
    } else if (empty) {
      state = 'empty'
    } else {
      state = 'synchronized'
      icon = <MdDone />
    }
    return (
      <div className={cx('user-profile__field-header-indicator', `user-profile__field-header-indicator_${state}`)}>
        {icon}
      </div>
    )
  }

  render_content() {
    let field = this.props
    let props = {
      ...field,
      update: (...input) => {
        let synchronisation_id = this.idGenerator++
        let toggle_synchronisation = () => this.setState(toggle_item_id(this.state, "synchronisations", synchronisation_id))
        toggle_synchronisation()
        field.update(...input)
        .then(toggle_synchronisation)
      }
    }
    switch (field.category) {
      case 'comment':
        return (
          <CommentField {...props} />
        )
      case 'non_exclusive':
        return (
          <NonExclusiveField {...props} />
        )
      case 'file':
        return (
          <FileField {...props} />
        )
      case 'exclusive':
        return (
          <ExclusiveField {...props} />
        )
    }
  }

  render() {
    let {name} = this.props
    return (
      <div className={cx('user-profile__field')}>
        <div className={cx('user-profile__field-header')}>
          {name}
          {this.render_indicator()}
        </div>
        {this.render_content()}
      </div>
    )
  }
}

class CommentField extends Component {
  constructor(props) {
    super(props)
    this.state = {
      comment: props.comment,
      focused: false,
    }
    this.onFocus = this.onFocus.bind(this)
    this.onChange = this.onChange.bind(this)
    this.onBlur = this.onBlur.bind(this)
  }

  onFocus() {
    this.setState({focused: true})
    this.initial_comment = this.state.comment
  }

  onChange({target: {value: comment}}) {
    if (!this.state.focused && comment != this.state.comment) {
      this.props.update(comment)
    }
    this.setState({comment})
  }

  onBlur() {
    this.setState({focused: false})
    if (this.state.comment != this.initial_comment) {
      this.props.update(this.state.comment)
    }
  }

  componentWillReceiveProps({comment}) {
    if (comment != this.state.comment && !this.state.focused) {
      this.setState({comment})
    }
  }

  render() {
    let {comment, focused} = this.state
    let className = cx('user-profile__field-input', {'user-profile__field-input_empty': !comment, 'user-profile__field-input_focused': focused})
    if (this.props.locked) {
      return (
        <div className={className}>
          {comment}
        </div>
      )
    } else {
      return (
        <input
          className={className}
          type="text"
          value={comment || ""}
          onFocus={this.onFocus}
          onChange={this.onChange}
          onBlur={this.onBlur}
          />
      )
    }
  }
}

CommentField.defaultProps = {
  comment: "",
}

class NonExclusiveField extends Component {
  constructor(props) {
    super(props)
    this.state = {
      width: 500,
    }
    this.update_width = this.update_width.bind(this)
    this.render_value = this.render_value.bind(this)
    this.toggle_value = this.toggle_value.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.values_container).width()
    if (width != this.state.width) {
      this.setState({width})
    }
  }

  toggle_value(index) {
    return () => {
      let {values, update} = this.props
      update([
        ...values.slice(0, index),
        property_toggler('selected')(values[index]),
        ...values.slice(index + 1),
      ])
    }
  }

  render_value(width) {
    return ({id, name, selected}, index) => (
      <div
        onClick={this.toggle_value(index)}
        key={id}
        className={cx('user-profile__field-values-value', {'user-profile__field-values-value_selected': selected})}
        style={{width}}
        >
        <div className={cx('user-profile__field-values-value-outline')}>
          <div className={cx('user-profile__field-values-value-name')}>
            {name}
          </div>
          <div className={cx('user-profile__field-values-value-icon')}>
            {selected ? (
              <MdDone />
            ) : null}
          </div>
        </div>
      </div>
    )
  }

  render() {
    let available_width = this.state.width
    let columns_number = Math.floor(available_width / value_width) || 1
    let width = `${100 / columns_number}%`
    let {values} = this.props
    return (
      <div
        ref={(values_container) => this.values_container = values_container}
        className={cx('user-profile__field-values')}
        >
        {values.map(this.render_value(width))}
      </div>
    )
  }
}

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

  on_files_drop([file]) {
    this.props.update(file)
  }

  view() {
    let {file: {url, name}} = this.props
    download_file(url, name)
  }

  render() {
    let {file} = this.props
    if (file) {
      if (file.uploading) {
        return (
          <ProgressIndicator small className={cx('user-profile__field-dropzone')} completed={file.uploading} total={100} text="##%"/>
        )
      } else {
        let {updated_at, url} = file
        return (
          <div className={cx('user-profile__field-file')}>
            <div onClick={this.view} className={cx('user-profile__field-file-preview')}>
              <MdInsertDriveFile />
            </div>
            <div className={cx('user-profile__field-file-updated-at')}>
              Mis à jour <TimeAgo>{updated_at}</TimeAgo>
            </div>
            <Dropzone style={{}} onDrop={this.on_files_drop}>
              <div className={cx('user-profile__field-file-update')}>
                Choisir un autre fichier
              </div>
            </Dropzone>
          </div>
        )
      }
    } else {
      return (
        <div className={cx('user-profile__field-dropzone')}>
          <FileDropzone on_files_drop={this.on_files_drop}>
            Déposer un fichier
          </FileDropzone>
        </div>
      )
    }
  }
}

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

  update(values) {
    const selected_value_id = this.get_selected_value_id()
    values.forEach((value) => {
      if (value.id == selected_value_id && !value.selected) {
        return this.props.update(null)
      }
      if (value.selected && value.id != selected_value_id) {
        return this.props.update(value)
      }
    })
    return new Promise((resolve, reject) => resolve())
  }

  get_selected_value_id() {
    const {value} = this.props
    const {id} = value || {}
    return id
  }

  render() {
    const {values} = this.props
    const selected_value_id = this.get_selected_value_id()
    return (
      <NonExclusiveField
        values={values.map((value) => ({...value, selected: value.id == selected_value_id}))}
        update={this.update}
      />
    )
  }
}

export default UserProfile
