package infrastructure

import (
	"git.markbailey.dev/cervers/ptpp/lib/database"
	"net/http"
	"sync"

	"git.markbailey.dev/cervers/ptpp/handlers"
	"git.markbailey.dev/cervers/ptpp/handlers/admin"
	"git.markbailey.dev/cervers/ptpp/lib/logger"
	mw "git.markbailey.dev/cervers/ptpp/lib/middleware"
	"git.markbailey.dev/cervers/ptpp/lib/session"
)

var (
	globalSessions *session.Manager
	commonRouter   *http.ServeMux
	adminStack     mw.Func
	commonStack    mw.Func
	lock           = &sync.Mutex{}
	il             logger.ILogger
)

func GetRouter() http.Handler {
	commonStack = mw.Compose(
		mw.WithLogger,
		mw.WithUsername,
	)

	if commonRouter == nil {
		lock.Lock()
		defer lock.Unlock()

		adminStack = mw.Compose(
			mw.WithAuth,
		)

		commonRouter = http.NewServeMux()
		adminRouter := http.NewServeMux()

		// Serve static files
		fs := http.FileServer(http.Dir("./public/"))
		commonRouter.Handle("GET /public/", http.StripPrefix("/public", fs))
		commonRouter.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
			http.ServeFile(w, r, "./public/assets/favicon/favicon.ico")
		})

		// Homepage routes
		homepageHandler := handlers.NewHomePageHandler(il)
		commonRouter.Handle("/", mw.ErrHandler(homepageHandler.Homepage))

		if env == "production" {
			return commonStack(commonRouter)
		}

		// User routes
		userHandler := handlers.NewUserHandler(il, globalSessions, database.ChooseDB())
		commonRouter.Handle("GET /signup", mw.ErrHandler(userHandler.SignUp))
		commonRouter.Handle("POST /signup", mw.ErrHandler(userHandler.SignUp))
		commonRouter.Handle("GET /signin", mw.ErrHandler(userHandler.SignIn))
		commonRouter.Handle("POST /signin", mw.ErrHandler(userHandler.SignIn))
		commonRouter.Handle("GET /signout", mw.ErrHandler(userHandler.SignOut))
		commonRouter.Handle("GET /populate", mw.ErrHandler(userHandler.Populate))

		// Admin routes
		adminIndexHandler := admin.NewAdminIndexHandler(il, globalSessions)
		adminRouter.Handle("GET /", mw.ErrHandler(adminIndexHandler.Index))
		commonRouter.Handle("/admin/", http.StripPrefix("/admin", adminStack(adminRouter)))
	}

	return commonStack(commonRouter)
}

func init() {
	globalSessions, _ = session.NewManager("memory", "ptpp", 3600)
	go globalSessions.GC()

	il = logger.NewCompositeLogger()
}
