package dispatchergrpcsvc

import (
	"context"

	"connectrpc.com/connect"

	"go.autokitteh.dev/autokitteh/internal/backend/muxes"
	"go.autokitteh.dev/autokitteh/internal/kittehs"
	"go.autokitteh.dev/autokitteh/proto"
	dispatcher1 "go.autokitteh.dev/autokitteh/proto/gen/go/autokitteh/dispatcher/v1"
	"go.autokitteh.dev/autokitteh/proto/gen/go/autokitteh/dispatcher/v1/dispatcherv1connect"
	"go.autokitteh.dev/autokitteh/sdk/sdkerrors"
	"go.autokitteh.dev/autokitteh/sdk/sdkservices"
	"go.autokitteh.dev/autokitteh/sdk/sdktypes"
)

type server struct {
	dispatcher sdkservices.Dispatcher

	dispatcherv1connect.UnimplementedDispatcherServiceHandler
}

var _ dispatcherv1connect.DispatcherServiceHandler = (*server)(nil)

func Init(muxes *muxes.Muxes, dispatcher sdkservices.Dispatcher) {
	srv := server{dispatcher: dispatcher}

	path, namer := dispatcherv1connect.NewDispatcherServiceHandler(&srv)
	muxes.Auth.Handle(path, namer)
}

func (s *server) Dispatch(ctx context.Context, req *connect.Request[dispatcher1.DispatchRequest]) (*connect.Response[dispatcher1.DispatchResponse], error) {
	msg := req.Msg

	if err := proto.Validate(msg); err != nil {
		return nil, sdkerrors.AsConnectError(err)
	}

	event, err := sdktypes.EventFromProto(msg.Event)
	if err != nil {
		return nil, sdkerrors.AsConnectError(err)
	}

	deploymentID, err := sdktypes.ParseDeploymentID(msg.DeploymentId)
	if err != nil {
		return nil, sdkerrors.AsConnectError(err)
	}

	resp, err := s.dispatcher.Dispatch(ctx, event, &sdkservices.DispatchOptions{DeploymentID: deploymentID, Wait: msg.Wait})
	if err != nil {
		return nil, connect.NewError(connect.CodeInvalidArgument, err)
	}

	return connect.NewResponse(&dispatcher1.DispatchResponse{EventId: resp.EventID.String(), SessionIds: kittehs.TransformToStrings(resp.SessionIDs)}), nil
}

func (s *server) Redispatch(ctx context.Context, req *connect.Request[dispatcher1.RedispatchRequest]) (*connect.Response[dispatcher1.RedispatchResponse], error) {
	msg := req.Msg

	if err := proto.Validate(msg); err != nil {
		return nil, sdkerrors.AsConnectError(err)
	}

	eventID, err := sdktypes.Strict(sdktypes.ParseEventID(msg.EventId))
	if err != nil {
		return nil, sdkerrors.AsConnectError(err)
	}

	deploymentID, err := sdktypes.Strict(sdktypes.ParseDeploymentID(msg.DeploymentId))
	if err != nil {
		return nil, sdkerrors.AsConnectError(err)
	}

	resp, err := s.dispatcher.Redispatch(ctx, eventID, &sdkservices.DispatchOptions{DeploymentID: deploymentID, Wait: msg.Wait})
	if err != nil {
		return nil, connect.NewError(connect.CodeInvalidArgument, err)
	}

	return connect.NewResponse(&dispatcher1.RedispatchResponse{EventId: resp.EventID.String(), SessionIds: kittehs.TransformToStrings(resp.SessionIDs)}), nil
}
