import React, {Component} from 'react'
import {
  MdSortByAlpha,
  MdCheck,
  MdPlace,
} from 'react-icons/lib/md'
import classNames from 'classnames/bind'
import FilterableTable from 'components/filterable_table/filterable_table'
import UserCard from 'components/user_card'
import Filter from 'components/filter'
import AddressPicker from 'components/address_picker'
import SearchBar from 'components/search_bar'
import {
  map_hash,
  distance,
  filter_hash,
  for_all,
  array_from_set,
  empty_set,
  empty_array,
} from 'common/utilities'
import {
  action_add_user_value,
  action_remove_user_value,
  action_update_user_comment,
  action_create_user_field,
} from 'common/fields'
import {new_users_fuse, make_user_statuses, get_user_status} from 'common/users'
import auto_bind from 'common/auto_bind'
import store from 'common/store'
import persistent_state from 'common/persistent_state'
import {tolerant_selector} from 'selectors/base'
import {get_user_fields} from 'selectors/fields'
import NonExclusiveFieldFilter from 'components/non_exclusive_field_filter'

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

const get_users = (_, props) => props.users
const get_fuse_users = tolerant_selector(
  [get_users],
  (users) => Object.keys(users).map((id) => users[id]).filter((user) => user.full_name != "")
)

class UserTable extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name_filtered_user_ids: [],
      name_query: "",
      place: props.place,
      radius_filter: null,
      users: props.users,
      selected_statuses: {...props.initial_selected_statuses},
      ...persistent_state.get(props.persistent_state_key),
    }
    auto_bind(this)
  }

  componentDidMount() {
    this.mounted = true
    this.update_distances()
    this.name_search_bar.set_query(this.state.name_query)
  }

  componentWillReceiveProps(props) {
    let place_has_changed = false
    if (props.place != this.props.place) {
      this.setState({place: props.place})
      place_has_changed = true
      this.order_by_distance()
    }
    if (place_has_changed || props.users !== this.props.users) {
      this.update_distances(props.users)
    }
  }

  componentWillUnmount() {
    this.mounted = false
    persistent_state.store(this.props.persistent_state_key, this.state)
  }

  on_name_query_change(query, results) {
    if (this.mounted) {
      this.setState({name_filtered_user_ids: results, name_query: query})
    }
  }

  update_distances(users) {
    if (!users) {
      users = this.props.users
    }
    this.setState({users: map_hash(users, (user) => {
      user = {...user, status: this.get_table_user_status(user)}
      if (this.state.place) {
        user.distance = distance(user, {
          latitude: this.state.place.location.lat,
          longitude: this.state.place.location.lng,
        })
      } else if (user.distance) {
        user.distance = null
      }
      return user
    })})
  }

  order_by(order_by, ascending) {
    if (this.mounted) {
      this.table.order_by(order_by, ascending)
    }
  }

  order_by_distance() {
    if (this.mounted) {
      this.table.order_by('distance', true)
    }
  }

  get_table_user_status(user) {
    if (user && user.status) {
      return user.status
    } else {
      return get_user_status(user)
    }
  }

  get_forbidden_statuses() {
    return {
      ...(this.props.forbidden_statuses || {}),
      applied: true,
    }
  }

  render() {
    let fields = filter_hash(this.props.fields, (field) => field.for_entity == 'User')
    let fake_state = {fields: {values: this.props.values, fields}, users: this.props}
    let filtered_user_ids = this.state.name_filtered_user_ids
    filtered_user_ids = filtered_user_ids.filter((id) => this.state.users[id])
    if (this.state.radius_filter && this.state.place) {
      filtered_user_ids = filtered_user_ids.filter((id) => {
        let user = this.state.users[id]
        return user.distance && user.distance < this.state.radius_filter * 1000
      })
    }
    filtered_user_ids = filtered_user_ids.filter((id) => {
      let user = this.state.users[id]
      return !this.get_forbidden_statuses()[this.get_table_user_status(user).status]
    })
    let existing_user_statuses = {}
    filtered_user_ids.forEach((user_id) => existing_user_statuses[this.state.users[user_id].status.status] = true)
    if (!empty_array(array_from_set(this.state.selected_statuses).filter((status) => existing_user_statuses[status]))) {
      filtered_user_ids = filtered_user_ids.filter((id) => {
        let user = this.state.users[id]
        return this.state.selected_statuses[this.get_table_user_status(user).status]
      })
    }
    return (
      <FilterableTable
        get_table_ref={(table) => this.table = table}
        {...this.props}
        persistent_state_key={this.props.persistent_state_key ? `${this.props.persistent_state_key}-inner` : ''}
        fields={fields}
        items={this.state.users}
        render_card={(user) => <UserCard selectable={this.props.selectable} selected={this.props.selected[user.id]} {...user} />}
        filtered_item_ids={filtered_user_ids}
        on_card_click={this.props.on_user_card_click}
        add_value={action_add_user_value}
        remove_value={action_remove_user_value}
        update_comment={action_update_user_comment}
        get_item_field_values={(item_id, field_id) => get_user_fields(item_id)(fake_state)[field_id].selected_values}
        item_type={'user'}
        filter_value={(value_id) => {
          let value = this.props.values[value_id]
          if (value) {
            return (id) => value.entity_ids[id]
          } else {
            return (id) => true
          }
        }}
        >
        <div className={cx('filterable-table__card-name-arrange')}>
          <div className={cx('filterable-table__sort-name')} onClick={() => this.table.order_by('full_name')}>
            <MdSortByAlpha />
          </div>
          <div className={cx('filterable-table__search-bar-container')}>
            <SearchBar
              ref={(name_search_bar) => this.name_search_bar = name_search_bar}
              className={cx('filterable-table__search-bar')}
              make_fuse={new_users_fuse}
              items={get_fuse_users({}, this.props)}
              default_results={Object.keys(this.props.users)}
              on_query_change={this.on_name_query_change}
              />
          </div>
        </div>
        <div className={cx('filterable-table__card-filters')}>
          {this.props.status_filterable ? (
            <NonExclusiveFieldFilter
              values={
                array_from_set(existing_user_statuses).map(
                  (id) => ({id, ...make_user_statuses(this.state.selected_statuses[id] ? 'white' : null)[id], selected: this.state.selected_statuses[id]})
                ).filter((status) => !this.get_forbidden_statuses()[status.id])
              }
              name={"Statut"}
              toggle_filtered_value={(status) => this.setState({selected_statuses: {...this.state.selected_statuses, [status.id]: !this.state.selected_statuses[status.id]}})}
              search_enabled={false}
            />
          ) : null}
          <Filter
            label={"Dernière connexion"}
            onClick={() => this.table.order_by('last_connection')}
            />
          {this.props.place_filterable ? (
            <PlaceFilter
              active={this.state.place !== null}
              place_selectable={this.props.place_selectable}
              onClick={this.props.place_selectable ? null : (() => this.order_by_distance())}
              on_place_select={(place) => {
                this.setState({place})
                this.update_distances()
                this.order_by_distance()
              }}
              on_clear_place_input={() => {
                this.setState({place: null})
                this.update_distances()
              }}
              on_radius_change={(radius_filter) => this.setState({radius_filter})}
              initial_query={this.state.place ? this.state.place.label : ""}
              />
          ) : null}
        </div>
      </FilterableTable>
    )
  }
}

class PlaceFilter extends Component {
  constructor(props) {
    super(props)
    this.state = {
      radius: "",
    }
  }

  render() {
    return (
      <Filter className={cx('filterable-table__filter')} active={this.props.active} label={<MdPlace />} onClick={this.props.onClick}>
        <div className={cx('filterable-table__filter-place')}>
          {this.props.place_selectable ? (
            <div className={cx('filterable-table__filter-place-group')}>
              <div className={cx('filterable-table__filter-place-label')}>
                Trier en fonction de la distance à
              </div>
              <div className={cx('filterable-table__filter-place-input')}>
                <AddressPicker {...this.props} />
              </div>
            </div>
          ) : null}
          <div className={cx('filterable-table__filter-place-group')}>
            <div className={cx('filterable-table__filter-place-label')}>
              Filtrer les candidats au delà de
            </div>
            <div className={cx('filterable-table__filter-place-input')}>
              <input
                ref={(radius_input) => this.radius_input = radius_input}
                type="text"
                placeholder=""
                className={cx('filterable-table__filter-place-radius-input')}
                value={this.state.radius}
                onChange={(event) => {
                  let radius = event.target.value
                  this.setState({radius})
                  this.props.on_radius_change(radius)
                }}
                />
              <div className={cx('filterable-table__filter-place-radius-unit')}>
                km
              </div>
            </div>
          </div>
        </div>
      </Filter>
    )
  }
}

UserTable.defaultProps = {
  items: {},
  fields: {},
  values: {},
  on_user_card_click: (user_id) => {},
  editable: true,
  selectable: false,
  place_filterable: true,
  place_selectable: true,
  status_filterable: true,
  place: null,
  selected: {},
  on_select_all: (filtered_item_ids) => {},
  store_field_name: (field_id, name) => {},
  delete_field: (field_id) => {},
  initial_selected_statuses: {},
  forbidden_statuses: {},
}

export default UserTable
