import {tolerant_selector} from 'selectors/base'
import {get_mission_proposals} from 'selectors/missions'
import {get_fields_by_shift, get_shifts_fields} from 'selectors/fields'
import moment from 'common/moment'
import {
  make_memoized, split_array, array_from_hash, property_getter, map_hash, compare,
} from 'common/utilities'
import {action_update_shift_events, action_create_shift} from 'common/shifts'

const get_raw_shifts = (state) => state.shifts.shifts
const get_raw_shift_events = (state) => state.shifts.events

const add_start_end = ({events, ...shift}) => {
  let min, max
  events.forEach(({start, end}) => {
    if (!min || min.isAfter(start)) {
      min = moment(start)
    }
    if (!max || max.isBefore(end)) {
      max = moment(end)
    }
  })
  return {
    ...shift,
    events,
    start: min,
    end: max,
    update_events(events) {
      action_update_shift_events(shift, events)
    },
  }
}

const get_events_by_shift = tolerant_selector(
  [get_raw_shift_events],
  (events) => split_array(
    array_from_hash(events).filter(({deleted_at}) => !deleted_at),
    property_getter('calenderable_id'),
  )
)

const get_shifts = tolerant_selector(
  [get_raw_shifts, get_events_by_shift, get_fields_by_shift],
  (shifts, events_by_shift, fields_by_shift) => map_hash(
    shifts,
    (shift) => add_start_end({
      ...shift,
      events: events_by_shift[shift.id] || [],
      fields: array_from_hash(fields_by_shift[shift.id]) || [],
    })
  )
)

const get_splitted_shifts = tolerant_selector(
  [get_shifts],
  (shifts) => map_hash(
    split_array(array_from_hash(shifts), property_getter('proposal_id')),
    (shifts) => split_array(shifts, property_getter('event_id'))
  )
)

export const get_proposal_shifts = make_memoized((proposal_id, mission_id) => tolerant_selector(
  [get_mission_proposals, get_splitted_shifts, get_shifts_fields],
  (missions, splitted_shifts, shifts_fields) => {
    const {events, create_shift} = missions[mission_id] || {}
    return (events || []).sort(compare(({start}) => moment(start).valueOf())).map(({start, end, id}) => {
      const [shift] = (splitted_shifts[proposal_id] || {})[id] || []
      const get_shift = () => new Promise((resolve, reject) => {
        if (shift) {
          resolve(shift)
        } else {
          action_create_shift(proposal_id, id).then(resolve, reject)
        }
      })
      let fields
      if (shift) {
        fields = shift.fields
      } else {
        fields = shifts_fields.map(({select_value, update_comment, fetch_value, ...field}) => ({
          ...field,
          on_select_value(value_id) {
            return get_shift().then((shift) => select_value(shift.id, value_id))
          },
          on_submit_comment(comment) {
            return get_shift().then((shift) => update_comment(shift.id, comment))
          },
          fetch_value() {
            return get_shift().then((shift) => fetch_value(shift.id))
          },
        }))
      }
      return {
        ...(shift || {}),
        theoretic: {start, end},
        real: shift,
        fields,
        update_events(events) {
          get_shift().then((shift) => action_update_shift_events(shift, events))
        },
      }
    })
  }
))
