//
// Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
// Ministerpräsidenten des Landes Schleswig-Holstein
// Staatskanzlei
// Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
//
// Lizenziert unter der EUPL, Version 1.2 oder - sobald
// diese von der Europäischen Kommission genehmigt wurden -
// Folgeversionen der EUPL ("Lizenz");
// Sie dürfen dieses Werk ausschließlich gemäß
// dieser Lizenz nutzen.
// Eine Kopie der Lizenz finden Sie hier:
//
// https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
//
// Sofern nicht durch anwendbare Rechtsvorschriften
// gefordert oder in schriftlicher Form vereinbart, wird
// die unter der Lizenz verbreitete Software "so wie sie
// ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
// ausdrücklich oder stillschweigend - verbreitet.
// Die sprachspezifischen Genehmigungen und Beschränkungen
// unter der Lizenz sind dem Lizenztext zu entnehmen.
//

package mock

import (
    log "github.com/sirupsen/logrus"
	pb "antragsraum-proxy/gen/go"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"io"
	"net"
	"os"
	"testing"
)

const (
	defaultFilePath = "internal/mock/testdata/dummy.pdf"
	testFilePath    = "testdata/dummy.pdf"
)

type rueckfrageServer struct {
	pb.UnimplementedAntragraumServiceServer
}

func (s *rueckfrageServer) FindRueckfragen(_ context.Context, in *pb.GrpcFindRueckfragenRequest) (*pb.GrpcFindRueckfragenResponse, error) {
	if in.PostfachId == "" {
		return nil, status.Error(codes.InvalidArgument, "Id is missing")
	}

	if in.PostfachId == "conflictId" {
		return nil, status.Error(codes.AlreadyExists, "Conflict id")
	} else if in.PostfachId == "unavailableId" {
		return nil, status.Error(codes.Unavailable, "Unavailable Id")
	} else if in.PostfachId == "erroneousId" {
		return nil, status.Error(codes.Internal, "Erroneous Id")
	}

	return &pb.GrpcFindRueckfragenResponse{}, nil
}

func (s *rueckfrageServer) GetRueckfrage(_ context.Context, in *pb.GrpcGetRueckfrageRequest) (*pb.GrpcGetRueckfrageResponse, error) {
	if in.Id == "" {
		return nil, status.Error(codes.InvalidArgument, "Id is missing")
	}

	return &pb.GrpcGetRueckfrageResponse{}, nil
}

func (s *rueckfrageServer) SendRueckfrageAnswer(_ context.Context, _ *pb.GrpcSendRueckfrageAnswerRequest) (*pb.GrpcSendRueckfrageAnswerResponse, error) {
	return &pb.GrpcSendRueckfrageAnswerResponse{}, nil
}

func (s *rueckfrageServer) GetAttachmentContent(_ *pb.GrpcGetAttachmentContentRequest, stream pb.AntragraumService_GetAttachmentContentServer) error {
	fp := defaultFilePath
	if testing.Testing() {
		fp = testFilePath
	}

	file, err := os.Open(fp)
	if err != nil {
		return err
	}
	defer file.Close()

	buffer := make([]byte, 1024*1024)
	for {
		bytesRead, err := file.Read(buffer)
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		chunk := &pb.GrpcGetAttachmentContentResponse{FileContent: buffer[:bytesRead]}
		if err := stream.Send(chunk); err != nil {
			return err
		}
	}

	return nil
}

func (s *rueckfrageServer) GetAttachmentMetadata(_ context.Context, in *pb.GrpcGetAttachmentMetadataRequest) (*pb.GrpcGetAttachmentMetadataResponse, error) {
	if in.FileId == "" {
		return nil, status.Error(codes.InvalidArgument, "FileId is missing")
	}

	return &pb.GrpcGetAttachmentMetadataResponse{}, nil
}

type commandServer struct {
	pb.UnimplementedCommandServiceServer
}

func (s *commandServer) GetCommand(_ context.Context, in *pb.GrpcGetCommandRequest) (*pb.GrpcCommand, error) {
	if in.Id == "" {
		return nil, status.Error(codes.InvalidArgument, "Id is missing")
	}

	return &pb.GrpcCommand{}, nil
}

type binaryFileServer struct {
	pb.UnimplementedBinaryFileServiceServer
}

func (s *binaryFileServer) UploadBinaryFileAsStream(stream pb.BinaryFileService_UploadBinaryFileAsStreamServer) error {
	for {
		_, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&pb.GrpcUploadBinaryFileResponse{FileId: "testFileId"})
		}

		if err != nil {
			return err
		}
	}
}

func StartGrpcServer() *grpc.Server {
	s := grpc.NewServer()
	pb.RegisterAntragraumServiceServer(s, &rueckfrageServer{})
	pb.RegisterCommandServiceServer(s, &commandServer{})
	pb.RegisterBinaryFileServiceServer(s, &binaryFileServer{})

	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", conf.Grpc.Server.Port))
	if err != nil {
		log.Fatal(fmt.Sprintf("gRPC server failed to listen: %v", err))
	}

	log.Info(fmt.Sprintf("gRPC server listening on port %v", conf.Grpc.Server.Port))
	if err := s.Serve(lis); err != nil {
		log.Fatal(fmt.Sprintf("gRPC server failed to serve: %v", err))
	}

	return s
}