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/paid-order/config"
	"github.com/UpmeshLTD/urus-aio/paid-order/docs"
	"github.com/UpmeshLTD/urus-aio/paid-order/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())

	i.registerRoutes(r)

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

	return r
}

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

func (i *serverImpl) registerRoutes(r *gin.Engine) {
	r.GET("/", i.svc.NewGetInfo())
	r.GET("/health-check", i.svc.NewHealthCheck())

	r.Use(func(c *gin.Context) {
		c.Set("Language", middleware.GetAcceptLanguage(c))
	})

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

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

	// Fulfillment
	userRoutes.GET("/fulfillments", i.svc.GetListOfFulfillments)
	userRoutes.GET("/fulfillments/:id", i.svc.GetFulfillment)
	userRoutes.POST("/fulfillments", i.svc.CreateFulfillment)
	userRoutes.POST("/fulfillments/:id", i.svc.CreateFulfillmentFromDraft)
	userRoutes.PATCH("/fulfillments/:id", i.svc.UpdateFulfillment)
	userRoutes.DELETE("/fulfillments/:id", i.svc.DeleteFulfillment)
	userRoutes.DELETE("/fulfillments/:id/orders/:paidOrderId", i.svc.DeleteOrderFromFulfillment)
	userRoutes.POST("/fulfillments/estimated-fee", i.svc.GetFulfillmentEstimatedFee)

	// Paid order
	userRoutes.GET("/paid-orders", i.svc.GetListPaidOrders)
	userRoutes.GET("/paid-orders/count", i.svc.CountDraftOrders)
	userRoutes.POST("/paid-orders/arrange-ship", i.svc.ArrangeShipPaidOrders)
	userRoutes.POST("/paid-orders/:cartId/archive", i.svc.ArchivePaidOrder)
	userRoutes.POST("/paid-orders/arranged-ship", i.svc.GetArrangedShipPaidOrders)
	userRoutes.POST("/paid-orders", i.svc.CreatePaidOrders)

	// Delivery Address - Seller
	userRoutes.POST("/delivery-addresses/by-seller", i.svc.CreateDeliveryAddressBySeller)
	userRoutes.GET("/delivery-addresses/:cartId/by-seller", i.svc.GetDeliveryAddressBySeller)
	userRoutes.PUT("/delivery-addresses/:cartId/recipient-name", i.svc.UpdateRecipientName)
	userRoutes.PUT("/delivery-addresses/:cartId/recipient-phone", i.svc.UpdateRecipientPhoneNumber)
	userRoutes.PUT("/delivery-addresses/:cartId/address", i.svc.UpdateAddress)
	userRoutes.GET("/delivery-addresses/:cartId/logs", i.svc.GetDeliveryAddressLogs)

	// Delivery Address - Buyer
	buyerRoutes.POST("/delivery-addresses", i.svc.CreateDeliveryAddressByBuyer)

	// Delivery Address - Guest
	r.GET("/delivery-addresses/:cartId", i.svc.GetDeliveryAddress)
	r.POST("/guest/delivery-addresses", i.svc.CreateDeliveryAddressByGuest)
}
