package handlers

import (
	"hamster-tycoon/middlewares"
	"hamster-tycoon/service"
	"hamster-tycoon/storage/dao"
	"hamster-tycoon/storage/dao/postgresql"
	"hamster-tycoon/storage/validators"
	"net/http"
	"time"

	"reflect"
	"strings"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"gopkg.in/go-playground/validator.v9"
)

type Config struct {
	Mock            bool
	DBConnectionURI string
	Port            int
	LogLevel        string
	LogFormat       string
}

type handlersContext struct {
	db             dao.Database
	validator      *validator.Validate
	userService    *service.UserService
	cageService    *service.CageService
	hamsterService *service.HamsterService
}

func NewRouter(config *Config) *gin.Engine {
	gin.SetMode(gin.ReleaseMode)

	router := gin.New()
	router.HandleMethodNotAllowed = true

	router.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"*"},
		AllowMethods:     []string{"*"},
		AllowHeaders:     []string{"*"},
		ExposeHeaders:    []string{"*"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))
	router.Use(gin.Recovery())
	router.Use(middlewares.GetLoggerMiddleware())
	router.Use(middlewares.GetHTTPLoggerMiddleware())

	hc := &handlersContext{}
	hc.db = postgresql.NewDatabasePostgreSQL(config.DBConnectionURI)

	hc.validator = newValidator()
	hc.userService = service.NewUserService(hc.db)
	hc.cageService = service.NewCageService(hc.db)
	hc.hamsterService = service.NewHamsterService(hc.db)

	public := router.Group("/")
	public.Handle(http.MethodGet, "/_health", hc.GetHealth)

	userRoute := public.Group("/users")
	userRoute.Handle("LOGIN", "", hc.connectUser)
	userRoute.Handle(http.MethodPost, "", hc.createUser)

	securedUserRoute := userRoute.Group("")
	//TODO add secure auth
	securedUserRoute.Handle(http.MethodGet, "", hc.getAllUsers)
	securedUserRoute.Handle(http.MethodGet, "/:userID", hc.getUser)
	//securedUserRoute.Handle(http.MethodPut, "/:userID", hc.updateUser)
	//securedUserRoute.Handle(http.MethodDelete, "/:userID", hc.deleteUser)
	// end: user routes

	cageRoute := securedUserRoute.Group("/cages")
	cageRoute.Handle(http.MethodGet, "", hc.getAllCages)
	cageRoute.Handle(http.MethodGet, "/:cageID", hc.getACage)
	//cageRoute.Handle(http.MethodPost, "/:cageID", hc.createACage)
	//cageRoute.Handle(http.MethodPut, "/:cageID", hc.updateACage)
	//cageRoute.Handle(http.MethodDelete, "/:cageID", hc.deleteACage)

	hamsterRoute := cageRoute.Group("/:cageID/hamsters")
	hamsterRoute.Handle(http.MethodGet, "", hc.getAllHamsters)
	hamsterRoute.Handle(http.MethodGet, "/:hamsterID", hc.getAHamster)
	//hamsterRoute.Handle(http.MethodPost, "/:hamsterID", hc.createAHamster)
	//hamsterRoute.Handle(http.MethodPut, "/:hamsterID", hc.updateAHamster)
	//hamsterRoute.Handle(http.MethodDelete, "/:hamsterID", hc.deleteAHamster)

	return router
}

func newValidator() *validator.Validate {
	va := validator.New()

	va.RegisterTagNameFunc(func(fld reflect.StructField) string {
		name := strings.SplitN(fld.Tag.Get("json"), ",", 2)
		if len(name) < 1 {
			return ""
		}
		return name[0]
	})

	for k, v := range validators.CustomValidators {
		if v.Validator != nil {
			va.RegisterValidationCtx(k, v.Validator)
		}
	}

	return va
}
