import {update_item, store_items} from './base'
import {
  set_from_array, array_from_set, set_difference, property_getter, flatten_array, map_hash,
  create_hash, filter_hash,
} from '../common/utilities'

const initial_state = {
  fields: {},
  values: {},
}

const sanitize_set = (set) => !set || Array.isArray(set) ? set_from_array(set || []) : set

const sanitize_value = ({entity_ids, mission_ids, ...value}) => ({
  ...map_hash({entity_ids, mission_ids}, sanitize_set),
  ...value,
})

const sanitize_field = ({values, ...field}) => ({
  values: set_from_array(values.map(property_getter('id'))),
  ...field,
})

const update_field = (state, {values, ...field}) => update_item(
  store_items(state, "values", (values || []).map(sanitize_value)),
  "fields",
  field,
)

const update_value = (state, {entity_ids, mission_ids, ...value}) => update_item(
  state,
  'values',
  {
    ...value,
    ...map_hash(filter_hash({entity_ids, mission_ids}, Boolean), set_from_array),
  }
)

const add_items_value = (state, value_id, item_ids, for_missions) => {
  const value = state.values[value_id]
  const ids_key = for_missions ? 'mission_ids' : 'entity_ids'
  return {
    ...state,
    values: {
      ...state.values,
      [value_id]: {
        ...value,
        [ids_key]: {
          ...value[ids_key],
          ...set_from_array(item_ids),
        },
      },
    },
  }
}

const make_update_clear_items_exclusive_value = () => create_hash(
  ['clear', 'update'],
  (verb) => (state, value_id, item_ids) => {
    const {field_id} = state.values[value_id] || {}
    const {value_id_for} = state.fields[field_id] || {}
    return update_item(state, "fields", {id: field_id, value_id_for: {
      ...value_id_for,
      ...create_hash(item_ids, () => verb == 'clear' ? null : value_id)
    }})
  }
)

const {
  update: update_items_exclusive_value,
  clear: clear_items_exclusive_value,
} = make_update_clear_items_exclusive_value()

const remove_items_value = (state, value_id, item_ids, for_missions) => {
  const value = state.values[value_id]
  const ids_key = for_missions ? 'mission_ids' : 'entity_ids'
  return {
    ...state,
    values: {
      ...state.values,
      [value_id]: {
        ...value,
        [ids_key]: set_difference(array_from_set(value[ids_key]), set_from_array(item_ids)),
      },
    },
  }
}

const update_items_comment = (state, field_id, comments) => {
  return update_item(state, "fields", {
    id: field_id,
    comments: {
      ...((state.fields[field_id] || {}).comments || {}),
      ...comments,
    },
  })
}

export function fields(state = initial_state, action) {
  let fields, values, value, field
  switch (action.type) {
    case "store_fields":
      return store_items(
        store_items(
          state,
          "values",
          flatten_array(action.fields.map(property_getter('values', []))).map(sanitize_value),
        ),
        "fields",
        action.fields.map(sanitize_field),
      )
    case "update_field":
      return update_field(state, action.field)
    case "update_fields":
      return action.fields.reduce(update_field, state)
    case "remove_field":
      fields = {...state.fields}
      delete fields[action.field_id]
      values = {...state.values}
      array_from_set(state.fields[action.field_id].values).forEach((id) => {
        delete values[id]
      })
      return {
        ...state,
        fields,
        values,
      }
    case "store_values":
      return {
        ...state,
        values: action.values.reduce((values, value) => ({
          ...values,
          [value.id]: sanitize_value(value),
        }), state.values),
        fields: action.values.reduce((fields, value) => ({
          ...fields,
          [value.field_id]: {
            ...state.fields[value.field_id],
            values: {
              ...state.fields[value.field_id].values,
              [value.id]: true,
            }
          }
        }), state.fields),
      }
    case "update_value":
      return update_value(state, action.value)
    case "update_values":
      return action.values.reduce(update_value, state)
    case "remove_value":
      values = {...state.values}
      delete values[action.value_id]
      field = state.fields[state.values[action.value_id].field_id]
      return {
        ...state,
        values,
        fields: {
          ...state.fields,
          [field.id]: {
            ...field,
            values: {
              ...field.values,
              [action.value_id]: false,
            }
          }
        }
      }
    case "add_users_value":
      return add_items_value(state, action.value_id, action.user_ids)
    case "remove_users_value":
      return remove_items_value(state, action.value_id, action.user_ids)
    case "add_entity_value":
      return add_items_value(state, action.value_id, [action.entity_id], action.for_missions)
    case "update_exclusive_entity_value":
      return update_items_exclusive_value(state, action.value_id, [action.entity_id])
    case "clear_exclusive_entity_value":
      return clear_items_exclusive_value(state, action.value_id, [action.entity_id])
    case "remove_entity_value":
      return remove_items_value(state, action.value_id, [action.entity_id], action.for_missions)
    case "update_user_comments":
      return update_items_comment(state, action.field_id, action.user_comments)
    case "update_entity_comment":
      return update_items_comment(state, action.field_id, {[action.entity_id]: action.comment})
    default:
      return state
  }
}
