package grpc

import (
	"context"
	"fmt"
	"log"
	"net"

	"github.com/UpmeshLTD/urus-aio/paid-order/config"
	"github.com/UpmeshLTD/urus-aio/paid-order/server/grpc/pb"
	"github.com/UpmeshLTD/urus-aio/paid-order/service"
	"go.opencensus.io/plugin/ocgrpc"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/types/known/emptypb"
)

//go:generate mockery --name=Server --inpackage --case=snake
type Server interface {
	Serve() error
}

func NewServer(
	svc service.Service,
	configProvider config.Config,
) Server {
	return &serverImpl{
		svc:            svc,
		configProvider: configProvider,
	}
}

type serverImpl struct {
	svc            service.Service
	configProvider config.Config
}

func (i *serverImpl) Serve() error {

	conf := i.configProvider.GetGRPCConfig()
	grpcListener, err := net.Listen("tcp", fmt.Sprintf(":%d", conf.Port))
	if err != nil {
		log.Printf("Listen GRPC error: %s", err.Error())
		return err
	}

	s := grpc.NewServer(
		grpc.StatsHandler(
			&ocgrpc.ServerHandler{},
		),
	)

	pb.RegisterPaidOrderServiceServer(s, &paidOrderService{
		svc: i.svc,
	})

	log.Printf(" 🚀 Listening GRPC on port %d", conf.Port)
	return s.Serve(grpcListener)
}

type paidOrderService struct {
	pb.UnimplementedPaidOrderServiceServer
	svc service.Service
}

func (i *paidOrderService) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) {
	return i.svc.Ping(ctx, req)
}

func (i *paidOrderService) GetFulfillmentByID(ctx context.Context, req *pb.GetFulfillmentRequest) (*pb.GetFulfillmentResponse, error) {
	return i.svc.GetFulfillmentByID(ctx, req)
}

func (i *paidOrderService) UpdateFulfillmentDraftStatus(ctx context.Context, req *pb.UpdateFulfillmentDraftStatusRequest) (*emptypb.Empty, error) {
	return new(emptypb.Empty), i.svc.UpdateFulfillmentDraftStatus(ctx, req)
}

func (i *paidOrderService) GetPaidOrders(ctx context.Context, req *pb.GetPaidOrdersRequest) (*pb.GetPaidOrderResponse, error) {
	return i.svc.GRPCGetPaidOrders(ctx, req)
}

func (i *paidOrderService) UpdatePaidOrderIncorrectInformation(ctx context.Context, req *pb.UpdatePaidOrderIncorrectInformationRequest) (*emptypb.Empty, error) {
	return new(emptypb.Empty), i.svc.UpdatePaidOrderIncorrectInformation(ctx, req)
}

func (i *paidOrderService) GetDeliveryAddressByCartID(ctx context.Context, req *pb.GetDeliveryAddressByCartIDRequest) (*pb.GetDeliveryAddressByCartIDResponse, error) {
	return i.svc.GetDeliveryAddressByCartID(ctx, req)
}

func (i *paidOrderService) GetDeliveryAddressByCartIDs(ctx context.Context, req *pb.GetDeliveryAddressByCartIDsRequest) (*pb.GetDeliveryAddressByCartIDsResponse, error) {
	return i.svc.GetDeliveryAddressByCartIDs(ctx, req)
}

func (i *paidOrderService) CancelArrangedShipPaidOrder(ctx context.Context, req *pb.CancelArrangedShipPaidOrderRequest) (*emptypb.Empty, error) {
	return new(emptypb.Empty), i.svc.CancelArrangedShipPaidOrder(ctx, req)
}

func (i *paidOrderService) UpdatePaidOrderShipmentId(ctx context.Context, req *pb.UpdatePaidOrderShipmentIdRequest) (*emptypb.Empty, error) {
	return new(emptypb.Empty), i.svc.UpdatePaidOrderShipmentId(ctx, req)
}

func (i *paidOrderService) ReArrangeShipPaidOrders(ctx context.Context, req *pb.ReArrangeShipPaidOrdersRequest) (*pb.ReArrangeShipPaidOrdersResponse, error) {
	return i.svc.ReArrangeShipPaidOrdersGRPC(ctx, req)
}
