package http

import (
	"chonho/config"
	"chonho/internal/api-v1/delivery/http-handler/controller"
	"chonho/internal/api-v1/delivery/http-handler/middleware"
	"chonho/internal/api-v1/repository/address_repository"
	"chonho/internal/api-v1/repository/apartment_repository"
	"chonho/internal/api-v1/repository/category_repository"
	"chonho/internal/api-v1/repository/fmc_repository"
	"chonho/internal/api-v1/repository/order_repository"
	"chonho/internal/api-v1/repository/product_repository"
	"chonho/internal/api-v1/repository/rate_repository"
	"chonho/internal/api-v1/repository/store_repository"
	"chonho/internal/api-v1/repository/user_repository"
	"chonho/internal/api-v1/usecase/apartment_usecase"
	"chonho/internal/api-v1/usecase/authentication_usecase"
	"chonho/internal/api-v1/usecase/category_usecase"
	"chonho/internal/api-v1/usecase/notification_usecase"
	"chonho/internal/api-v1/usecase/order_usecase"
	"chonho/internal/api-v1/usecase/product_usecase"
	"chonho/internal/api-v1/usecase/seller_order_usecase"
	"chonho/internal/api-v1/usecase/store_usecase"
	"chonho/internal/api-v1/usecase/user_usecase"
	"chonho/migration"
	"chonho/pkg/db"
	"fmt"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func InitHttp() *gin.Engine {

	// connect to database
	fmt.Printf(config.DbConnStr)
	db, err := db.NewDatabase(config.DbConnStr, 10, 2)
	if err != nil {
		panic("no db connection")
	}

	migration.CreateTable(db)

	r := gin.New()
	cf := cors.DefaultConfig()
	cf.AllowAllOrigins = true
	cf.AllowCredentials = true
	cf.AddAllowHeaders("X-Api-Version")
	cf.AddAllowHeaders("X-App-Version")
	cf.AddAllowHeaders("X-App-Platform")
	cf.AddAllowHeaders("X-App-Device-Id")
	cf.AddAllowHeaders("Authorization")
	r.Use(gin.Recovery())
	r.Use(cors.New(cf))
	r.Use(middleware.CheckApiVersion)
	r.Use(middleware.LogResponse)

	// init general repository
	apartmentRepo := apartment_repository.NewApartmentRepository(db)
	categoryRepo := category_repository.NewCategoryRepository(db)
	userRepo := user_repository.NewUserRepository(db)
	addressRepo := address_repository.NewAddressRepository(db)
	productRepo := product_repository.NewProductRepository(db)
	storeRepo := store_repository.NewStoreRepository(db)
	rateRepo := rate_repository.NewRateRepository(db)
	orderRepo := order_repository.NewOrderRepository(db)
	fcmRepo := fmc_repository.NewFCMRepository(db)

	authUseCase := authentication_usecase.NewAuthenticationUseCase(config.JWTKey, config.TokenLifeTime, userRepo, addressRepo, config.ServiceAccount, storeRepo, fcmRepo)
	notifyUseCase := notification_usecase.NewNotifyUsCase(orderRepo, userRepo, storeRepo, fcmRepo)

	handler := NewHandler(
		WithGinEngine(r),
		WithAuthUseCase(authUseCase),
	)
	authController := controller.NewAuthenticationController(authUseCase)
	handler.AuthController = authController

	apartmentController := controller.NewApartmentController(apartment_usecase.NewApartmentUseCase(apartmentRepo))
	handler.ApartmentController = apartmentController

	categoryController := controller.NewCategoryController(category_usecase.NewCategoryUseCase(categoryRepo))
	handler.CategoryController = categoryController

	productUseCase := product_usecase.NewProductUseCase(productRepo, storeRepo, categoryRepo)
	handler.SellerProductController = controller.NewSellerProductController(productUseCase)
	handler.ProductController = controller.NewProductController(productUseCase)

	storeUseCase := store_usecase.NewStoreUseCase(storeRepo, rateRepo)
	handler.SellerStoreController = controller.NewSellerStoreController(storeUseCase)
	handler.StoreController = controller.NewStoreController(storeUseCase)

	addressUseCase := user_usecase.NewUserUseCase(addressRepo, userRepo, fcmRepo)
	handler.UserController = controller.NewUserController(addressUseCase)

	orderUseCase := order_usecase.NewOrderUseCase(orderRepo, productRepo, addressRepo, notifyUseCase)
	handler.OrderController = controller.NewOrderController(orderUseCase)

	sellerOrderUseCase := seller_order_usecase.NewSellerOrderUseCase(orderRepo, storeRepo, notifyUseCase)
	handler.SellerOrderController = controller.NewSellerOrderController(sellerOrderUseCase)

	handler.UploadController = controller.NewUploadController()

	handler.InitRoute()

	return r
}
