import axios from 'axios'
import handleApiError from '../handleApiError'

const cloneMinimalShowObject = function (show) {
  /* returns a new minimal object from the current show object with all
  properties needed for a PUT request to the /show/ endpoint */
  let s = {}
  s.name = show.name
  s.slug = show.slug
  s.short_description = show.short_description
  s.fundingcategory = show.fundingcategory
  s.type = show.type
  // we do not want the arrays do be passed as references, because the
  // current show object should not get modified when the update object
  // gets modified, therefore we use slice to clone the arrays
  s.category = show.category.slice()
  s.hosts = show.hosts.slice()
  s.owners = show.owners.slice()
  s.language = show.language.slice()
  s.topic = show.topic.slice()
  s.musicfocus = show.musicfocus.slice()
  return s
}

const state = {
  shows: [],
  schedule: null,
  schedules: [],
  scheduleTimeslots: [],
  timeslots: [],
  notes: [],
  types: [],
  fundingcategories: [],
  categories: [],
  topics: [],
  musicfocus: [],
  languages: [],
  hosts: [],
  loaded: {
    shows: false,
    timeslots: false,
    notes: false,
    schedule: false,
    scheduleTimeslots: false,
    schedules: false,
    types: false,
    fundingcategories: false,
    categories: false,
    topics: false,
    musicfocus: false,
    languages: false,
    hosts: false,
  },
  selected: {
    index: 0, // index of the currently selected show in our shows array
    id: 0,    // actual id of the currently selected show
  }
}

const getters = {
  shows: state => state.shows,
  selectedShow: state => state.shows[state.selected.index],
  schedule: state => state.schedule,
  schedules: state => state.schedules,
  scheduleTimeslots: state => state.scheduleTimeslots,
  timeslots: state => state.timeslots,
  notes: state => state.notes,
  types: state => state.types,
  fundingcategories: state => state.fundingcategories,
  categories: state => state.categories,
  topics: state => state.topics,
  musicfocus: state => state.musicfocus,
  languages: state => state.languages,
  hosts: state => state.hosts,
  getShowByDataParam: state => data => {
    let show
    if (data.id !== undefined) {
      show = state.shows.find(s => s.id === data.id)
      if (show === undefined) {
        console.log('[ERROR] getShowByDataParam: ID not found in store!')
      }
    } else if (data.index !== undefined) {
      show = state.shows[data.index]
    } else {
      console.log('[ERROR] getShowByDataParam: no ID or index was provided')
    }
    return show
  },
  getTimeslotById: state => id => {
    return state.timeslots.find(s => s.id === id)
  }
}

const mutations = {
  loading(state, item) { state.loaded[item] = false },
  finishLoading(state, item) { state.loaded[item] = true },

  setShows(state, shows) { state.shows = shows },
  addShow (state, show) {
    state.shows.push(show)
    state.shows.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase())
  },

  setSchedule (state, schedule) { state.schedule = schedule },
  setSchedules (state, schedules) { state.schedules = schedules },
  setScheduleTimeslots (state, slots) { state.scheduleTimeslots = slots },

  setTimeslots(state, slots) { state.timeslots = slots },
  setTimeslot(state, slot) {
    let index = state.timeslots.findIndex(s => s.id === slot.id)
    state.timeslots.splice(index, 1, slot)
  },

  setNotes(state, notes) { state.notes = notes },
  addNote(state, note) { state.notes.push(note) },
  setNote(state, note) {
    let index = state.notes.findIndex(n => n.id === note.id)
    state.notes.splice(index, 1, note)
  },

  setName (state, data) {
    let index = state.shows.findIndex(s => s.id === data.id)
    state.shows[index].name = data.text
  },
  setShortDescription (state, data) {
    let index = state.shows.findIndex(s => s.id === data.id)
    state.shows[index].short_description = data.text
  },
  setDescription (state, data) {
    let index = state.shows.findIndex(s => s.id === data.id)
    state.shows[index].description = data.text
  },
  setActive (state, data) {
    let index = state.shows.findIndex(s => s.id === data.id)
    state.shows[index].is_active = data.active
  },
  setProperty (state, data) {
    let index = state.shows.findIndex(s => s.id === data.id)
    state.shows[index][data.property] = data.value
  },

  setMetaArray (state, data) { state[data.property] = data.value },

  switchShow (state, index) {
    if (state.loaded.shows) {
      state.selected.index = index
      state.selected.id = state.shows[index].id
    }
  },
  switchShowById (state, id) {
    if (state.loaded.shows) {
      state.selected.index = state.shows.findIndex(s => s.id === id)
      state.selected.id = id
    }
  },
}

const actions = {
  fetchShows (ctx, data) {
    const user = ctx.rootState.auth.user.steeringUser;
    ctx.commit('loading', 'shows')
    let uri = process.env.VUE_APP_API_STEERING + 'shows'
    // normal users should only see their own shows, only superusers see all shows
    if (user && !user.is_superuser) {
      uri += '?owner=' + ctx.rootState.auth.user.steeringUser.id
    }
    axios.get(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('setShows', response.data)
      ctx.commit('finishLoading', 'shows')
      if (data && typeof(data.callback) === 'function') { data.callback() }
    }).catch(error => {
      handleApiError(this, error, 'could not load shows')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  fetchSchedule (ctx, data) {
    ctx.commit('loading', 'schedule')
    let uri = process.env.VUE_APP_API_STEERING + 'shows/' + data.show +
      '/schedules/' + data.schedule + '/'
    axios.get(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('setSchedule', response.data)
      ctx.commit('finishLoading', 'schedule')
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not load schedule')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  fetchSchedules (ctx, data) {
    ctx.commit('loading', 'schedule')
    let uri = process.env.VUE_APP_API_STEERING + 'shows/' + data.show + '/schedules/'

    axios.get(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('setSchedules', response.data)
      ctx.commit('finishLoading', 'schedule')
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not load schedule')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  fetchTimeslots (ctx, data) {
    if (data.schedule !== undefined) { ctx.commit('loading', 'scheduleTimeslots') }
    else { ctx.commit('loading', 'timeslots') }

    let uri
    if (data.id !== undefined) {
      uri = process.env.VUE_APP_API_STEERING + 'shows/' + data.id
      if (data.schedule !== undefined) {
        uri += '/schedules/' + data.schedule + '/timeslots/?'
      } else {
        uri += '/timeslots/?'
      }
    } else {
      uri = process.env.VUE_APP_API_STEERING + 'timeslots?'
    }
    uri += 'start=' + data.start
    uri += '&end=' + data.end
    if (data.limit) { uri += '&limit=' + data.limit }
    if (data.offset) { uri += '&offset=' + data.offset }

    axios.get(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      if (data.schedule !== undefined) {
        ctx.commit('setScheduleTimeslots', response.data)
        ctx.commit('finishLoading', 'scheduleTimeslots')
      } else {
        if (data.limit) {
          ctx.commit('setTimeslots', response.data.results)
        } else {
          ctx.commit('setTimeslots', response.data)
        }
        ctx.commit('finishLoading', 'timeslots')
      }
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not load timeslots')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  fetchNotes (ctx, data) {
    ctx.commit('loading', 'notes')
    // we only have to make an API call if there are actually any notes
    // otherwise the notes are just and empty array
    if (data.notes.length === 0) {
      ctx.commit('setNotes', [])
      ctx.commit('finishLoading', 'notes')
      return
    }
    let uri = process.env.VUE_APP_API_STEERING_SHOWS + data.id + '/notes/?ids='
    for (let id of data.notes) {
      uri += id + ','
    }
    uri = uri.slice(0, -1) // now remove trailing ','
    this.$log.debug('fetchNotes: uri:', uri)
    axios.get(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('setNotes', response.data)
      ctx.commit('finishLoading', 'notes')
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not load notes')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  fetchMetaArray (ctx, data) {
    ctx.commit('loading', data.property)
    let uri = process.env.VUE_APP_API_STEERING + data.property + '/'
    if (data.onlyActive === true) {
      uri += '?active=true'
    }
    axios.get(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('setMetaArray', {property: data.property, value: response.data})
      ctx.commit('finishLoading', data.property)
      if (data && typeof(data.callback) === 'function') { data.callback() }
    }).catch(error => {
      handleApiError(this, error, 'could not load ' + data.property)
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  submitSchedule (ctx, data) {
    ctx.commit('loading', 'schedules')
    let uri = process.env.VUE_APP_API_STEERING_SHOWS + data.showId + '/schedules/'
    axios.post(uri, data.schedule, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('finishLoading', 'schedules')
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not load timeslots')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  submitShow (ctx, data) {
    let uri = process.env.VUE_APP_API_STEERING_SHOWS
    axios.post(uri, data.show , {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('addShow', response.data)
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not add new show')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  submitNote (ctx, data) {
    let uri = process.env.VUE_APP_API_STEERING_SHOWS + data.id +
    '/schedules/' + data.scheduleID +
    '/timeslots/' + data.timeslotID +
    '/note/'
    if (data.update) {
      uri += data.note.id + '/'
    }
    let method = data.update ? 'put' : 'post'
    axios.request({
      url: uri,
      method: method,
      data: data.note,
      withCredentials: true,
      responseType: 'json',  // we need this explicitly here, as it does not seem to work automagically as in GET and PUT requests
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      if (data.update) {
        ctx.commit('setNote', response.data)
      } else {
        ctx.commit('addNote', response.data)
      }
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      let msg = data.update ? 'could not update note' : 'could not add new note'
      handleApiError(this, error, msg)
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  updateShow (ctx, data) {
    let uri = process.env.VUE_APP_API_STEERING_SHOWS + data.id + '/'
    axios.put(uri, data.show , {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not update show')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  updateProperty (ctx, data) {
    let show = cloneMinimalShowObject(ctx.getters.getShowByDataParam(data))
    show[data.property] = data.value
    ctx.dispatch('updateShow', {
      id: data.id,
      show: show,
      callback: () => {
        ctx.commit('setProperty', {
          id: data.id,
          property: data.property,
          value: data.value
        })
        if (typeof(data.callback) === 'function') { data.callback() }
      }
    })
  },

  updateImage (ctx, data) {
    let show = ctx.getters.getShowByDataParam(data)
    let uri = process.env.VUE_APP_API_STEERING_SHOWS + data.id + '/'
    let formData = new FormData()
    // these propoerties have to be sent always (and they must not be null)
    formData.append('name', show.name)
    formData.append('slug', show.slug)
    formData.append('short_description', show.short_description)
    formData.append('type', show.type)
    formData.append('fundingcategory', show.fundingcategory)
    formData.append('is_active', show.is_active)
    // now we append the new logo/image file (signified by data.type)
    formData.append(data.type, data.file, data.file.name)
    axios.put(uri, formData , {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(response => {
      ctx.commit('setProperty', {
        id: data.id,
        property: data.type,
        // when updating images of a show the steering API does not return
        // the full URI but only the path on the server
        // TODO: create an issue in steering, to create consistency
        value: process.env.VUE_APP_BASEURI_STEERING + response.data[data.type]
      })
      if (data && typeof(data.callback) === 'function') { data.callback(response) }
    }).catch(error => {
      handleApiError(this, error, 'could not update show ' + data.type)
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  updateTimeslot (ctx, data) {
    let uri = process.env.VUE_APP_API_STEERING + 'shows/' + data.show +
      '/schedules/' + data.schedule +
      '/timeslots/' + data.timeslot.id + '/'
    axios.put(uri, data.timeslot, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(() => {
      ctx.commit('setTimeslot', data.timeslot)
      if (data && typeof(data.callback) === 'function') { data.callback() }
    }).catch(error => {
      handleApiError(this, error, 'could not update timeslot')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })

  },

  deleteSchedule (ctx, data) {
    let uri = process.env.VUE_APP_API_STEERING +
      'shows/' + data.show +
      '/schedules/' + data.schedule + '/'
    axios.delete(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(() => {
      if (data && typeof(data.callback) === 'function') { data.callback() }
    }).catch(error => {
      handleApiError(this, error, 'could not delete full schedule')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

  deleteTimeslot (ctx, data) {
    let uri = process.env.VUE_APP_API_STEERING +
      'shows/' + data.show +
      '/schedules/' + data.schedule +
      '/timeslots/' + data.timeslot + '/'
    axios.delete(uri, {
      withCredentials: true,
      headers: { 'Authorization': 'Bearer ' + ctx.rootState.auth.user.access_token }
    }).then(() => {
      if (data && typeof(data.callback) === 'function') { data.callback() }
    }).catch(error => {
      handleApiError(this, error, 'could not delete single timeslot')
      if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
    })
  },

}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations,
}