package response

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"gitlab.ost.ch/marketminds/marketminds/pkg/entity"
)

type Response struct {
	readOnly bool
	context  *gin.Context
	status   Status
	message  Message
	session  string

	newsChannels []*newsChannel
	newsChannel  *newsChannel

	pagination *pagination
	newsItem   *newsItem

	namedEntities []*namedEntity
	namedEntity   *namedEntity

	serviceStatus *ServiceStatus
}

func NewResponse(context *gin.Context) *Response {
	return &Response{
		readOnly: false,
		context:  context,
		status:   newStatus(http.StatusOK),
		message:  newMessage(),
		session:  "",
	}
}

func (r *Response) Respond() {
	if r := recover(); r != nil {
		panic(r)
	}

	response := gin.H{
		"status": r.status,
	}

	if r.message.Message != "" {
		response["message"] = r.message
	}

	if !r.message.IsError() {
		switch {
		case r.newsChannels != nil:
			response["newsChannels"] = r.newsChannels
		case r.newsChannel != nil:
			response["newsChannel"] = r.newsChannel
		case r.pagination != nil:
			response["pagination"] = r.pagination
		case r.newsItem != nil:
			response["newsItem"] = r.newsItem
		case r.namedEntities != nil:
			response["namedEntities"] = r.namedEntities
		case r.namedEntity != nil:
			response["namedEntity"] = r.namedEntity
		case r.serviceStatus != nil:
			response["serviceStatus"] = r.serviceStatus
		}
	}

	r.context.AbortWithStatusJSON(r.status.Code, response)
}

func (r *Response) Error(code int, message string) {
	if r.readOnly {
		return
	}
	r.message.SetMessage(errorMessage, message)
	r.status = newStatus(code)
	r.readOnly = true
}

func (r *Response) Warning(code int, message string) {
	if r.readOnly {
		return
	}
	r.message.SetMessage(warningMessage, message)
	r.status = newStatus(code)
}

func (r *Response) Info(code int, message string) {
	if r.readOnly {
		return
	}
	r.message.SetMessage(infoMessage, message)
	r.status = newStatus(code)
}

func (r *Response) Status(code int) {
	if r.readOnly {
		return
	}
	r.status = newStatus(code)
}

func (r *Response) SetSession(token string) {
	if r.readOnly {
		return
	}
	if token == "" {
		return
	}
	r.session = token
	r.readOnly = true
}

func (r *Response) SetNewsChannels(newsChannels ...*entity.NewsChannel) {
	if r.readOnly {
		return
	}
	if r.newsChannels == nil {
		r.newsChannels = make([]*newsChannel, 0, len(newsChannels))
	}
	for _, newsChannel := range newsChannels {
		r.newsChannels = append(r.newsChannels, newNewsChannel(newsChannel))
	}
	r.readOnly = true
}

func (r *Response) SetNewsChannel(newsChannel *entity.NewsChannel) {
	if r.readOnly {
		return
	}
	r.newsChannel = newNewsChannel(newsChannel)
	r.readOnly = true
}

func (r *Response) SetPagination(data []*entity.NewsItem, page int, pageSize int) {
	if r.readOnly {
		return
	}
	var newsItems []*newsItem
	if r.pagination == nil {
		newsItems = make([]*newsItem, 0, len(data))
	}
	for _, newsItem := range data {
		newsItems = append(newsItems, newNewsItem(newsItem))
	}
	r.pagination = newPagination(newsItems, page, pageSize)
	r.readOnly = true
}

func (r *Response) SetNewsItem(newsItem *entity.NewsItem) {
	if r.readOnly {
		return
	}
	r.newsItem = newNewsItem(newsItem)
	r.readOnly = true
}

func (r *Response) SetNamedEntities(namedEntities ...*entity.NamedEntity) {
	if r.readOnly {
		return
	}
	if r.namedEntities == nil {
		r.namedEntities = make([]*namedEntity, 0, len(namedEntities))
	}
	for _, namedEntity := range namedEntities {
		r.namedEntities = append(r.namedEntities, newNamedEntity(namedEntity))
	}
	r.readOnly = true
}

func (r *Response) SetNamedEntity(namedEntity *entity.NamedEntity) {
	if r.readOnly {
		return
	}
	r.namedEntity = newNamedEntity(namedEntity)
	r.readOnly = true
}

func (r *Response) SetServiceStatus(aiServiceStatus string) {
	if r.readOnly {
		return
	}
	r.serviceStatus = newServiceStatus(aiServiceStatus)
	r.readOnly = true
}
