package databag

import (
	"databag/internal/store"
	"net/http"
	"strconv"
)

func reverseTopics(input []store.TopicSlot) []store.TopicSlot {
	var output []store.TopicSlot
	for i := len(input) - 1; i >= 0; i-- {
		output = append(output, input[i])
	}
	return output
}

//GetChannelTopics retrieves topics associated with channel
func GetChannelTopics(w http.ResponseWriter, r *http.Request) {
	var revisionSet bool
	var revision int64
	var beginSet bool
	var begin int64
	var endSet bool
	var end int64
	var countSet bool
	var count int

	channelSlot, _, code, err := getChannelSlot(r, false)
	if err != nil {
		ErrResponse(w, code, err)
		return
	}

	rev := r.FormValue("revision")
	if rev != "" {
		revisionSet = true
		if revision, err = strconv.ParseInt(rev, 10, 64); err != nil {
			ErrResponse(w, http.StatusBadRequest, err)
			return
		}
	}

	cnt := r.FormValue("count")
	if cnt != "" {
		countSet = true
		if count, err = strconv.Atoi(cnt); err != nil {
			ErrResponse(w, http.StatusBadRequest, err)
			return
		}
	}

	bn := r.FormValue("begin")
	if bn != "" {
		beginSet = true
		if begin, err = strconv.ParseInt(bn, 10, 64); err != nil {
			ErrResponse(w, http.StatusBadRequest, err)
			return
		}
	}

	en := r.FormValue("end")
	if en != "" {
		endSet = true
		if end, err = strconv.ParseInt(en, 10, 64); err != nil {
			ErrResponse(w, http.StatusBadRequest, err)
			return
		}
	}

	response := []*Topic{}
	if revisionSet {
		var slots []store.TopicSlot
		if beginSet && !endSet {
			if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ? AND id >= ?", channelSlot.Channel.ID, revision, begin).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		} else if !beginSet && endSet {
			if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ? AND id < ?", channelSlot.Channel.ID, revision, end).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		} else if beginSet && endSet {
			if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ? AND id >= ? AND id < ?", channelSlot.Channel.ID, revision, begin, end).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		} else {
			if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ?", channelSlot.Channel.ID, revision).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		}
		for _, slot := range slots {
			response = append(response, getTopicRevisionModel(&slot))
		}
	} else {
		var slots []store.TopicSlot
		if countSet {
			if !endSet {
				if err := store.DB.Preload("Topic.Assets").Where("channel_id = ?", channelSlot.Channel.ID).Order("id desc").Limit(count).Find(&slots).Error; err != nil {
					ErrResponse(w, http.StatusInternalServerError, err)
					return
				}
			} else {
				if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id < ?", channelSlot.Channel.ID, end).Order("id desc").Limit(count).Find(&slots).Error; err != nil {
					ErrResponse(w, http.StatusInternalServerError, err)
					return
				}
			}
			slots = reverseTopics(slots)
		} else if beginSet && !endSet {
			if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id >= ?", channelSlot.Channel.ID, begin).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		} else if !beginSet && endSet {
			if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id < ?", channelSlot.Channel.ID, end).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		} else if beginSet && endSet {
			if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id >= ? AND id < ?", channelSlot.Channel.ID, begin, end).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		} else {
			if err := store.DB.Preload("Topic.Assets").Where("channel_id = ?", channelSlot.Channel.ID).Find(&slots).Error; err != nil {
				ErrResponse(w, http.StatusInternalServerError, err)
				return
			}
		}
		for _, slot := range slots {
			if slot.Topic != nil {
				if countSet {
					w.Header().Set("topic-marker", strconv.FormatUint(uint64(slot.ID), 10))
					countSet = false
				}
				response = append(response, getTopicModel(&slot))
			}
		}
	}

  if !endSet {
	  w.Header().Set("topic-revision", strconv.FormatInt(channelSlot.Revision, 10))
  }
	w.Header().Set("Access-Control-Expose-Headers", "*")
	WriteResponse(w, response)
}