package ginserver

import (
	"net/http"
	"time"

	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/handler"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/account"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/expense"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/storage/dao/postgresql"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/user"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/middleware"

	"github.com/gin-gonic/gin"

	"github.com/gin-contrib/cors"
)

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

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

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

	db := postgresql.NewDatabasePostgreSQL(config.DBConnectionURI)
	hc := handler.NewContext()
	uh := user.NewHandler(hc, db)
	ah := account.NewHandler(hc, db)
	eh := expense.NewHandler(hc, db)
	mv := middleware.NewValidator(hc, db)
	public := router.Group("/")
	public.Handle(http.MethodGet, "/_health", hc.GetHealth)

	userRoute := public.Group("/users")
	userRoute.Handle("GET", "", uh.ConnectUser)
	userRoute.Handle(http.MethodPost, "", uh.CreateUser)

	securedUserRoute := userRoute.Group("/")
	securedUserRoute.Use(middleware.ValidateOAuthToken)
	//TODO add secure auth
	securedUserRoute.Handle(http.MethodGet, "/:userId", uh.GetUser)

	securedMatchingToken := securedUserRoute.Group("/:userId")
	securedMatchingToken.Use(mv.HasValidUserId)
	securedMatchingToken.Use(mv.UserdIdMatchOAuthToken)
	//account route
	securedMatchingToken.Handle(http.MethodGet, "/accounts", ah.GetAllAccountOfUser)
	securedMatchingToken.Handle(http.MethodPost, "/accounts", ah.CreateAccountOfUser)

	securedValidAccount := securedMatchingToken.Group("/accounts/:accountId")
	securedValidAccount.Use(mv.HasValidAccountId)
	securedValidAccount.Use(mv.AccountExists)
	securedValidAccount.Handle(http.MethodDelete, "", ah.DeleteAccountOfUser)
	securedValidAccount.Handle(http.MethodGet, "", ah.GetSpecificAccountOfUser)
	securedValidAccount.Handle(http.MethodPost, "/expenses", eh.CreateAnExpense)
	securedValidAccount.Handle(http.MethodGet, "/expenses", eh.GetAllExpenses)

	securedExistingExpenses := securedValidAccount.Group("/expenses/:expenseId")
	securedExistingExpenses.Handle(http.MethodGet, "", eh.GetAnExpenses)
	securedExistingExpenses.Handle(http.MethodDelete, "", eh.DeleteExpense)
	return router
}
