package route

// |@@| C

import (
	"gardening/src/lib"
	"gardening/src/lib/config"
	"gardening/src/lib/dev_tool"
	erro2 "gardening/src/lib/error"
	"gardening/src/lib/fetcher"
	"gardening/src/lib/in_context"
	"gardening/src/lib/message"
	"gardening/src/lib/out_extra"
	"gardening/src/srv/layouts"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"gitlab.com/ccyrillee/kitcla/goc"
	"gitlab.com/ccyrillee/kitcla/goc_debug"
	"net/http"
	"net/url"
	"strings"
)

type AppRoute struct {
	Layout  *layouts.Layout
	DevTool *dev_tool.DevTool
	Config  *config.Config
}

func (this *AppRoute) PopulateInContext(c *gin.Context, inContext *in_context.InContext) {
	inContext.Location = c.Request.URL.RequestURI()
}

func (this *AppRoute) RenderView(c *gin.Context, view func() goc.HTML, extra *out_extra.OutExtra) {
	extra.Messages = this.CombineMessages(c, extra.Messages)
	root := view()
	s := goc.RenderRoot(root)
	s = "<!DOCTYPE html>\n" + s
	c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(s))
	if this.Config.IsDevEnv() {
		this.DevTool.Data.GocDebug = goc_debug.ExportDebug(root)
	}
}

func (this *AppRoute) CombineMessages(c *gin.Context, maeMessage []*message.Message) []*message.Message {
	session := sessions.Default(c)
	var messages []*message.Message
	for _, m := range maeMessage {
		messages = append(messages, &message.Message{
			Title: m.Title,
			Body:  m.Body,
			Kind:  m.Kind,
		})
	}
	flashes := session.Flashes()
	err := session.Save()
	lib.Poe(err)
	for _, flash := range flashes {
		flashData := strings.Split(flash.(string), "|")
		messages = append(messages, &message.Message{
			Title: flashData[1],
			Body:  "",
			Kind:  flashData[0],
		})
	}
	return messages
}

// Deprecated
func (this *AppRoute) AddMessage(c *gin.Context, title string, kind string) {
	session := sessions.Default(c)
	session.AddFlash(kind + "|" + title)
	err := session.Save()
	lib.Poe(err)
}

func (this *AppRoute) SaveMessagesIntoSession(c *gin.Context, messages []*message.Message) {
	session := sessions.Default(c)
	for _, m := range messages {
		session.AddFlash(m.Kind + "|" + m.Title)
	}
	err := session.Save()
	lib.Poe(err)
}

func (this *AppRoute) Redirect(c *gin.Context, extra *out_extra.OutExtra, location string) {
	if c.Query("redirect") != "" {
		c.Redirect(http.StatusFound, c.Query("redirect"))
		return
	}
	if c.PostForm("_redirect") != "" {
		c.Redirect(http.StatusFound, c.PostForm("_redirect"))
		return
	}
	if extra != nil && extra.Op != nil {
		c.Redirect(http.StatusFound, "/display-op?id="+extra.Op.Id)
		return
	}
	c.Redirect(http.StatusFound, location)
}

func (this *AppRoute) GetId(c *gin.Context) string {
	return c.Query("id")
}

func (this *AppRoute) ExtractRawFiltersFromUrl(c *gin.Context) []fetcher.RawFilter {
	var filters []fetcher.RawFilter

	query := c.Request.URL.RawQuery
	decoded, err := url.QueryUnescape(query)
	lib.Poe(err)
	params := strings.Split(decoded, "&")
	if len(params) < 1 {
		return filters
	}
	var filtersFieldsParams []string
	for _, param := range params {
		if strings.HasPrefix(param, "filters[fields]") {
			value := strings.TrimPrefix(param, "filters[fields]")
			filtersFieldsParams = append(filtersFieldsParams, value)
		}
	}
	for _, param := range filtersFieldsParams {
		ss := strings.Split(param, "=")
		keysString := ss[0]
		value := ss[1]
		keysString = strings.TrimPrefix(keysString, "[")
		keysString = strings.TrimSuffix(keysString, "]")
		keys := strings.Split(keysString, "][")
		filter := fetcher.RawFilter{
			Type:      "fields",
			Key:       keys[0],
			Operation: keys[1],
			Value:     value,
		}
		filters = append(filters, filter)
	}
	return filters
}

func (this *AppRoute) CanRenderView(err error) bool {
	e, ok := err.(*erro2.Error)
	if !ok {
		return false
	}
	if e.Kind == "validator.invalid_form" {
		return true
	}
	return false
}

func (this *AppRoute) RenderError(c *gin.Context, err error) {
	panic(err)
}
