package edge

import (
	"bytes"
	"net/http"
	"net/http/httputil"
	"net/url"

	"github.com/gin-gonic/gin"

	"gitlab.com/dynaweb/ains-microservices/pkg/config"
	"gitlab.com/dynaweb/ains-microservices/pkg/i18n"
	"gitlab.com/dynaweb/ains-microservices/pkg/jwt"
	"gitlab.com/dynaweb/ains-microservices/web"
)

const langCookieName = "ains_lang"

type Handler struct {
	view       *web.View
	cfg        *config.Config
	tokens     *jwt.Manager
	translator *i18n.Translator
	authProxy  *httputil.ReverseProxy
}

func NewHandler(view *web.View, cfg *config.Config, tokens *jwt.Manager, translator *i18n.Translator) (*Handler, error) {
	target, err := url.Parse(cfg.Auth.Upstream)
	if err != nil {
		return nil, err
	}
	return &Handler{
		view:       view,
		cfg:        cfg,
		tokens:     tokens,
		translator: translator,
		authProxy:  httputil.NewSingleHostReverseProxy(target),
	}, nil
}

func (h *Handler) Register(r gin.IRouter) error {
	if err := web.RegisterStatic(r, "/static"); err != nil {
		return err
	}
	r.GET("/", func(c *gin.Context) { h.render(c, "home", "home") })
	r.GET("/reading-center", func(c *gin.Context) { h.render(c, "reading-center", "reading-center") })
	r.GET("/web/:page", h.webPage)
	r.GET("/lang", h.lang)
	r.GET("/api/ping", h.ping)
	r.Any("/auth/*path", func(c *gin.Context) { h.authProxy.ServeHTTP(c.Writer, c.Request) })
	return nil
}

func (h *Handler) webPage(c *gin.Context) {
	page := c.Param("page")
	h.render(c, page, page)
}

func (h *Handler) render(c *gin.Context, page, active string) {
	if !h.view.HasPage(page) {
		c.String(http.StatusNotFound, "not found")
		return
	}
	lang := h.langValue(c)
	data := web.Data{
		Lang:   lang,
		Active: active,
		Title:  h.translator.T(lang, "home.title"),
		User:   h.user(c),
	}
	var buf bytes.Buffer
	if err := h.view.Render(&buf, http.StatusOK, page, data); err != nil {
		c.String(http.StatusInternalServerError, "render error")
		return
	}
	c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes())
}

func (h *Handler) lang(c *gin.Context) {
	lang := c.Query("lang")
	if lang != "ms" && lang != "en" {
		lang = h.cfg.I18n.DefaultLanguage
	}
	http.SetCookie(c.Writer, &http.Cookie{
		Name:     langCookieName,
		Value:    lang,
		Path:     "/",
		MaxAge:   31536000,
		HttpOnly: true,
	})
	redir := c.GetHeader("Referer")
	if redir == "" {
		redir = "/"
	}
	c.Redirect(http.StatusFound, redir)
}

func (h *Handler) ping(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"status": "pong", "service": "edge"})
}

func (h *Handler) langValue(c *gin.Context) string {
	if cookie, err := c.Cookie(langCookieName); err == nil && cookie != "" {
		return cookie
	}
	return h.cfg.I18n.DefaultLanguage
}

func (h *Handler) user(c *gin.Context) *web.UserCtx {
	raw, err := c.Cookie(h.cfg.Auth.CookieName)
	if err != nil || raw == "" {
		return nil
	}
	claims, err := h.tokens.ParseAccess(raw)
	if err != nil {
		return nil
	}
	return &web.UserCtx{
		UserID: claims.UserID,
		Role:   claims.Role,
		State:  claims.State,
		PPD:    claims.PPD,
		School: claims.School,
	}
}
