package http

import (
	"fmt"
	"log"
	"net/http"

	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"

	"github.com/UpmeshLTD/urus-aio/infrastructure/server/transport/http/gin/middleware"
	"github.com/UpmeshLTD/urus-aio/mdm/config"
	"github.com/UpmeshLTD/urus-aio/mdm/docs"
	"github.com/UpmeshLTD/urus-aio/mdm/service"
	"github.com/gin-gonic/gin"
	"go.opencensus.io/plugin/ochttp"
)

//go:generate mockery --name=Server --inpackage --case=snake
type Server interface {
	Serve() error
}

type serverImpl struct {
	server *http.Server
	svc    service.Service
	config config.Config
}

func NewServer(svc service.Service, config config.Config) Server {
	i := &serverImpl{
		svc:    svc,
		config: config,
	}

	i.initServer()
	return i
}

func (i *serverImpl) Serve() error {
	log.Printf(" 🚀 Listening HTTP on port %d", i.config.GetHTTPConfig().Port)
	return i.server.ListenAndServe()
}

func (i *serverImpl) initServer() {
	gin.SetMode(i.config.GetHTTPConfig().Mode)
	r := i.initRouter()

	srv := &http.Server{
		Addr: fmt.Sprintf(":%d", i.config.GetHTTPConfig().Port),
		Handler: &ochttp.Handler{
			Handler:          r,
			IsPublicEndpoint: true,
		},
	}
	i.server = srv
}

func (i *serverImpl) initRouter() *gin.Engine {
	r := gin.Default()
	r.Use(middleware.NewCORSMiddleware())
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, map[string]string{
			"version": "1",
		})
	})

	r.GET("/", i.svc.NewGetInfo())
	r.GET("/health-check", i.svc.NewHealthCheck())

	r.GET("/countries", i.svc.GetCountries)
	r.GET("/countries/:id/locations", i.svc.GetLocations)

	if i.config.GetAppConfig().Environment == "development" {
		i.initSwagger()
		r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	}

	buyerRoutes := r.Group("")
	buyerRoutes.Use(middleware.NewBuyerAuthMiddleware(i.config.GetAuthConfig().Buyer.Host, i.config.GetAuthConfig().Buyer.Port))

	sellerRoutes := r.Group("")
	sellerMiddleware := middleware.NewSellerAuthMiddleware(i.config.GetAuthConfig().User.Host, i.config.GetAuthConfig().User.Port)
	sellerRoutes.Use(sellerMiddleware)

	buyerRoutes.GET("/buyer-addresses", i.svc.GetBuyerAddresses)
	buyerRoutes.GET("/buyer-addresses/:id", i.svc.GetBuyerAddressByID)
	buyerRoutes.POST("/buyer-addresses", i.svc.CreateBuyerAddress)
	buyerRoutes.PUT("/buyer-addresses/:id", i.svc.UpdateBuyerAddress)
	buyerRoutes.DELETE("/buyer-addresses/:id", i.svc.DeleteBuyerAddress)

	// Draft checkout info
	buyerRoutes.POST("/draft-checkout-info", i.svc.SaveDraftCheckoutInfo)
	buyerRoutes.GET("/draft-checkout-info/:cartId", i.svc.GetDraftCheckoutInfoByBuyer)
	sellerRoutes.GET("/draft-checkout-info/:cartId/by-seller", i.svc.GetDraftCheckoutInfoBySeller)

	return r
}

func (i *serverImpl) initSwagger() {
	docs.SwaggerInfo.Host = i.config.GetSwaggerConfig().Host
	docs.SwaggerInfo.BasePath = i.config.GetSwaggerConfig().BasePath
}
