package app

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/AlchemyTelcoSolutions/callisto-so-bff/cmd/app/config"
	"github.com/AlchemyTelcoSolutions/callisto-so-bff/cmd/app/handler"
	"github.com/AlchemyTelcoSolutions/callisto-so-bff/internal/api"
	"github.com/AlchemyTelcoSolutions/callisto-so-bff/internal/auth"
	"github.com/AlchemyTelcoSolutions/callisto-so-bff/internal/proxy"
	"github.com/AlchemyTelcoSolutions/callisto-so-bff/internal/sale_order"
	"github.com/AlchemyTelcoSolutions/callisto-so-bff/pkg/logger"
	SOProto "github.com/AlchemyTelcoSolutions/proto/gen/go/callisto/so/v1"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)

func (a *App) initHTTPServer(ctx context.Context) (*http.Server, error) {
	proxySvc := setProxyService(a, ctx)
	// init service dependencies here
	authService := setAuthService(a, ctx, proxySvc)

	saleOrderService := setSaleOrderService(a, ctx, proxySvc, authService)

	server := api.NewServer(api.ServerOptions{
		Logger:       a.logger,
		SaleOrderSvc: saleOrderService,
		ProxySvc:     proxySvc,
		AuthSvc:      authService,
		Config:       a.config.(*config.Config),
	})

	h, err := handler.NewHandler(ctx, handler.Config{
		Logger:               a.logger,
		Server:               server,
		CallistoSOGrpcClient: a.clients.callistoSOGrpcClient,
		CallistAPIClient:     a.clients.callistoAPIClient,
		Configurations:       a.config,
	})

	if err != nil {
		return nil, errors.Wrap(err, "error setting up handler")
	}
	c := a.config.GetConfigurations()

	a.logger.Info("setup http server", zap.String("port", fmt.Sprintf("%v", c.HTTP.Port)))

	return &http.Server{
		Addr:              fmt.Sprintf("%s:%v", c.HTTP.Host, c.HTTP.Port),
		Handler:           h,
		ReadHeaderTimeout: time.Duration(c.HTTP.ReadHeaderTimeout * 1000),
	}, nil
}

// setSaleOrderService is a function to set the Sale Order Service
func setSaleOrderService(a *App, ctx context.Context, proxySvc *proxy.Service, authSvc auth.AuthService) *sale_order.Service {
	l := logger.
		New(a.logger).
		AddContextTag("ctx", "Sale Order Handler")

	callistoSoService := SOProto.NewSaleOrderServiceClient(a.clients.callistoSOGrpcClient)
	soService := sale_order.NewSaleOrderService().
		SetLogger(l).
		SetConfigs(a.config).
		SetProxyService(proxySvc).
		SetAuthService(authSvc).
		SetCallistoSOGRPC(callistoSoService)
	return soService
}

// setProxyService is a function to set the Proxy Service
func setProxyService(a *App, ctx context.Context) *proxy.Service {
	l := logger.
		New(a.logger).
		AddContextTag("ctx", "callisto api proxy")

	proxySvc := proxy.NewProxyService().
		SetLogger(l).
		SetConfigs(a.config).
		SetHttpClient(a.clients.callistoAPIClient)
	return proxySvc

}

// setAuthService is a function to set the Auth Service
func setAuthService(a *App, ctx context.Context, proxySvc *proxy.Service) *auth.Service {
	l := logger.
		New(a.logger).
		AddContextTag("ctx", "auth service")

	authSvc := auth.NewAuthService().
		SetLogger(l).
		SetConfigs(a.config).
		SetProxyService(proxySvc)

	return authSvc
}
