package quic

import (
	"context"
	"fmt"
	"io"
	"time"

	"zombiezen.com/go/capnproto2/rpc"

	"github.com/cloudflare/cloudflared/tunnelrpc"
	"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
)

// SessionManagerServer handles streams with the SessionManager RPCs.
type SessionManagerServer struct {
	sessionManager  pogs.SessionManager
	responseTimeout time.Duration
}

func NewSessionManagerServer(sessionManager pogs.SessionManager, responseTimeout time.Duration) *SessionManagerServer {
	return &SessionManagerServer{
		sessionManager:  sessionManager,
		responseTimeout: responseTimeout,
	}
}

func (s *SessionManagerServer) Serve(ctx context.Context, stream io.ReadWriteCloser) error {
	signature, err := determineProtocol(stream)
	if err != nil {
		return err
	}
	switch signature {
	case rpcStreamProtocolSignature:
		break
	case dataStreamProtocolSignature:
		return errDataStreamNotSupported
	default:
		return fmt.Errorf("unknown protocol %v", signature)
	}

	// Every new quic.Stream request aligns to a new RPC request, this is why there is a timeout for the server-side
	// of the RPC request.
	ctx, cancel := context.WithTimeout(ctx, s.responseTimeout)
	defer cancel()

	transport := tunnelrpc.SafeTransport(stream)
	defer transport.Close()

	main := pogs.SessionManager_ServerToClient(s.sessionManager)
	rpcConn := rpc.NewConn(transport, rpc.MainInterface(main.Client))
	defer rpcConn.Close()

	select {
	case <-rpcConn.Done():
		return rpcConn.Err()
	case <-ctx.Done():
		return ctx.Err()
	}
}
