package server

import (
	cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi"
	rpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/plugin-registry"
	"code.fbi.h-da.de/danet/gosdn/controller/app"
	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement"
	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
	rbacInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
	"code.fbi.h-da.de/danet/gosdn/controller/store"
	"code.fbi.h-da.de/danet/gosdn/controller/topology"
	"code.fbi.h-da.de/danet/gosdn/controller/topology/nodes"
	"code.fbi.h-da.de/danet/gosdn/controller/topology/ports"
	routingtables "code.fbi.h-da.de/danet/gosdn/controller/topology/routing-tables"

	"code.fbi.h-da.de/danet/gosdn/controller/metrics"
	"github.com/google/uuid"
	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// NorthboundInterface is the representation of the
// gRPC services used provided.
type NorthboundInterface struct {
	Pnd                     *PndServer
	Csbi                    *CsbiServer
	Plugin                  *PluginInternalServer
	Auth                    *AuthServer
	User                    *UserServer
	Role                    *RoleServer
	Topology                *TopologyServer
	App                     *AppServer
	NetworkElement          *NetworkElementServer
	Routes                  *RoutingTableServiceServer
	ConfigurationManagement *ConfigurationManagementServer
}

// NewNBI receives a PndStore and returns a new gRPC *NorthboundInterface.
func NewNBI(
	pnds networkdomain.PndStore,
	pndService networkdomain.Service,
	mneService networkelement.Service,
	changeStore store.ChangeStore,
	users rbacInterfaces.UserService,
	roles rbacInterfaces.RoleService,
	jwt rbac.JWTManager,
	topologyService topology.Service,
	nodeService nodes.Service,
	portService ports.Service,
	routeService routingtables.Service,
	apps app.ManagementService,
	pluginService plugin.Service,
	pluginRegistryClient rpb.PluginRegistryServiceClient,
	csbiClient cpb.CsbiServiceClient,
	pndCallbackFn func(uuid.UUID, chan networkelement.Details),
) *NorthboundInterface {
	return &NorthboundInterface{
		Pnd:                     NewPndServer(pndService, pluginService, pndCallbackFn, csbiClient),
		Csbi:                    NewCsbiServer(pnds),
		Plugin:                  NewPluginInternalServer(pluginRegistryClient, pluginService),
		Auth:                    NewAuthServer(&jwt, users),
		User:                    NewUserServer(&jwt, users),
		Role:                    NewRoleServer(&jwt, roles),
		Topology:                NewTopologyServer(topologyService, nodeService, portService),
		App:                     NewAppServer(apps),
		NetworkElement:          NewNetworkElementServer(mneService, pndService, pluginService, changeStore),
		Routes:                  NewRoutingTableServiceServer(routeService, nodeService, portService),
		ConfigurationManagement: NewConfigurationManagementServer(pndService, mneService, topologyService, nodeService, portService, pluginService),
	}
}

func handleRPCError(labels prometheus.Labels, err error) error {
	log.Error(err)
	return status.Errorf(codes.Aborted, "%v", metrics.HandleError(labels, err, grpcAPIErrorsTotal))
}
