// Copyright (C) 2019 Marius Schellenberger

package server

import (
	"bytes"
	"context"
	"errors"
	"git.giftfish.de/ston1th/godrop/v2"
	"git.giftfish.de/ston1th/gowiki/pkg/core"
	"git.giftfish.de/ston1th/gowiki/pkg/db"
	"git.giftfish.de/ston1th/gowiki/pkg/log"
	"git.giftfish.de/ston1th/jwt/v3"
	"github.com/gorilla/mux"
	"html/template"
	"net"
	"net/http"
	"time"
)

const (
	cookieName = "gowiki_session"
)

type HTTPServer struct {
	Config core.Config

	listener net.Listener
	srv      *http.Server

	DB  *db.DB
	JWT *jwt.JWT

	templ map[string]*template.Template
	res   map[string][]byte
}

func NewHTTPServer(cfg core.Config, l net.Listener) (srv *HTTPServer) {
	srv = &HTTPServer{
		Config:   cfg,
		listener: l,
	}
	srv.loadTemplates()
	srv.srv = &http.Server{
		Handler: srv.buildRoutes(),
	}
	return
}

func (s *HTTPServer) Start() (err error) {
	s.DB, err = db.New(s.Config)
	if err != nil {
		return errors.New("db: " + err.Error())
	}
	err = godrop.UnveilBlock()
	if err != nil {
		return
	}
	if s.Config.Secret != "" {
		s.JWT, err = jwt.New(jwt.DefaultExpiry, s.DB, bytes.NewBufferString(s.Config.Secret))
	} else {
		s.JWT, err = jwt.New(jwt.DefaultExpiry, s.DB, nil)
	}
	if err != nil {
		return errors.New("server: " + err.Error())
	}
	go func() {
		log.Println(s.srv.Serve(s.listener))
	}()
	return
}

func (s *HTTPServer) Stop() error {
	s.DB.Close()
	s.JWT.Stop()
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	defer cancel()
	return s.srv.Shutdown(ctx)
}

func (s *HTTPServer) buildRoutes() http.Handler {
	m := mux.NewRouter()
	m.NotFoundHandler = &notFoundHandler{s}
	for _, v := range static {
		m.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
	}
	for _, v := range routes {
		m.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
	}
	return m
}
func (s *HTTPServer) contextWrapper(h ctxHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		h(newContext(w, r, s))
	}
}
