package httpserver

import (
	"fmt"

	"git.gocasts.ir/ebhomengo/niki/config"
	adminhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/admin"
	adminagenthandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/agent"
	adminbenefactorhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/benefactor"
	adminKindBoxHandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/kind_box"
	adminkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/kind_box_req"
	adminrefertimehandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/refer_time"
	adminseedhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/admin/seed"
	agentkindboxhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/agent/kind_box"
	agentkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/agent/kind_box_req"
	benefactoraddresshandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/address"
	benefactorhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/benefactor"
	benefactorkindboxhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/kind_box"
	benefactorkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/kind_box_req"
	benefactorrefertimehandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/refer_time"
	"git.gocasts.ir/ebhomengo/niki/docs"
	"git.gocasts.ir/ebhomengo/niki/service"
	echo "github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	echoSwagger "github.com/swaggo/echo-swagger"
)

type Server struct {
	config                      config.Config
	Router                      *echo.Echo
	adminHandler                adminhandler.Handler
	adminKindBoxReqHandler      adminkindboxreqhandler.Handler
	adminKindBoxHandler         adminKindBoxHandler.Handler
	adminAgentHandler           adminagenthandler.Handler
	adminBenefactorHandler      adminbenefactorhandler.Handler
	adminReferTimeHandler       adminrefertimehandler.Handler
	agentKindBoxHandler         agentkindboxhandler.Handler
	agentKindBoxReqHandler      agentkindboxreqhandler.Handler
	benefactorHandler           benefactorhandler.Handler
	benefactorKindBoxReqHandler benefactorkindboxreqhandler.Handler
	benefactorAddressHandler    benefactoraddresshandler.Handler
	benefactorKindBoxHandler    benefactorkindboxhandler.Handler
	benefactorReferTimeHandler  benefactorrefertimehandler.Handler
	adminSeedHandler            adminseedhandler.Handler
}

func New(
	cfg config.Config,
	svc *service.Service,
) *Server {
	return &Server{
		Router:                      echo.New(),
		config:                      cfg,
		adminHandler:                adminhandler.New(svc.AdminAuthSvc, svc.AdminSvc, svc.AdminAuthorizeSvc),
		adminKindBoxReqHandler:      adminkindboxreqhandler.New(svc.AdminAuthSvc, svc.AdminKindBoxReqSvc, svc.AdminBenefactorAggSvc, svc.AdminAddressAggSvc, svc.AdminReferTimeAggSvc, svc.AdminAuthorizeSvc, svc.NotificationSvc),
		adminKindBoxHandler:         adminKindBoxHandler.New(svc.AdminAuthSvc, svc.AdminKindBoxSvc, svc.AdminBenefactorAggSvc, svc.AdminAddressAggSvc, svc.AdminReferTimeAggSvc, svc.AdminAuthorizeSvc, svc.NotificationSvc),
		adminAgentHandler:           adminagenthandler.New(svc.AdminAuthSvc, svc.AdminAgentSvc, svc.AdminAuthorizeSvc),
		adminBenefactorHandler:      adminbenefactorhandler.New(svc.AdminAuthSvc, svc.AdminAuthorizeSvc, svc.AdminBenefactorSvc, svc.AdminAddressSvc, svc.AdminKindBoxSvc, svc.AdminKindBoxReqSvc),
		adminReferTimeHandler:       adminrefertimehandler.New(svc.AdminAuthSvc, svc.AdminReferTimeSvc, svc.AdminAuthorizeSvc),
		adminSeedHandler:            adminseedhandler.New(svc.AdminAuthSvc, svc.AdminSeedSvc),
		agentKindBoxHandler:         agentkindboxhandler.New(svc.AdminAuthSvc, svc.AgentKindBoxSvc, svc.AdminAuthorizeSvc, svc.NotificationSvc),
		agentKindBoxReqHandler:      agentkindboxreqhandler.New(svc.AdminAuthSvc, svc.AgentKindBoxReqSvc, svc.AdminAuthorizeSvc, svc.NotificationSvc),
		benefactorHandler:           benefactorhandler.New(svc.BenefactorAuthSvc, svc.BenefactorSvc),
		benefactorKindBoxReqHandler: benefactorkindboxreqhandler.New(svc.BenefactorAuthSvc, svc.BenefactorKindBoxReqSvc, svc.NotificationSvc),
		benefactorAddressHandler:    benefactoraddresshandler.New(svc.BenefactorAuthSvc, svc.BenefactorAddressSvc),
		benefactorKindBoxHandler:    benefactorkindboxhandler.New(svc.BenefactorAuthSvc, svc.BenefactorKindBoxSvc, svc.NotificationSvc),
		benefactorReferTimeHandler:  benefactorrefertimehandler.New(svc.BenefactorAuthSvc, svc.BenefactorReferTimeSvc),
	}
}

func (s Server) Serve() {
	s.RegisterRoutes()

	// Start server
	address := fmt.Sprintf(":%d", s.config.HTTPServer.Port)
	fmt.Printf("start echo server on %s\n", address)
	if err := s.Router.Start(address); err != nil {
		fmt.Println("router start error", err)
	}
}

func (s Server) RegisterRoutes() {
	s.Router.Use(middleware.RequestID())
	s.Router.Use(middleware.Recover())
	s.Router.Use(middleware.CORSWithConfig(middleware.CORSConfig{
		AllowOrigins: s.config.HTTPServer.Cors.AllowOrigins,
	}))
	registerSwagger(s.Router)

	// Routes
	s.Router.GET("/health-check", s.healthCheck)
	s.benefactorHandler.SetRoutes(s.Router)
	s.benefactorKindBoxReqHandler.SetRoutes(s.Router)
	s.benefactorAddressHandler.SetRoutes(s.Router)
	s.benefactorKindBoxHandler.SetRoutes(s.Router)
	s.benefactorReferTimeHandler.SetRoutes(s.Router)
	s.adminHandler.SetRoutes(s.Router)
	s.adminAgentHandler.SetRoutes(s.Router)
	s.adminKindBoxReqHandler.SetRoutes(s.Router)
	s.adminKindBoxHandler.SetRoutes(s.Router)
	s.adminReferTimeHandler.SetRoutes(s.Router)
	s.adminBenefactorHandler.SetRoutes(s.Router)
	s.agentKindBoxHandler.SetRoutes(s.Router)
	s.agentKindBoxReqHandler.SetRoutes(s.Router)
	s.adminSeedHandler.SetRoutes(s.Router)
}

func registerSwagger(s *echo.Echo) {
	// TODO: move this to a better place and make it more dynamic and configurable
	docs.SwaggerInfo.Title = "NIKI API"
	docs.SwaggerInfo.Description = "This is the API documentation for the NIKI project"
	docs.SwaggerInfo.Version = "1.0.0"

	s.GET("/swagger/*any", echoSwagger.WrapHandler)
}
