package transport

import (
	"context"
	"git.sch9.ru/new_gate/ms-tester/internal/models"
	problemv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/problem/v1"
	sessionv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/session/v1"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/timestamppb"
	"net"
	"time"

	"google.golang.org/grpc"
)

type ProblemService interface {
	CanCreateProblem(ctx context.Context) error
	CreateProblem(ctx context.Context, problem *models.Problem) (int32, error)
	ReadProblemById(ctx context.Context, id int32) (*models.Problem, error)
	UpdateProblem(ctx context.Context, problem *models.Problem) error
	DeleteProblem(ctx context.Context, id int32) error
}

type SessionClient interface {
	Read(ctx context.Context,
		in *sessionv1.ReadSessionRequest,
		opts ...grpc.CallOption,
	) (*sessionv1.ReadSessionResponse, error)
}

type UserService interface {
	CreateUser(ctx context.Context, user *models.User) error
	ReadUserById(ctx context.Context, userId int32) (*models.User, error)
}

type TesterServer struct {
	problemv1.UnimplementedProblemServiceServer
	problemService ProblemService

	sessionClient SessionClient
	userService   UserService

	grpcServer *grpc.Server
	logger     *zap.Logger
}

func NewTesterServer(
	problemService ProblemService,
	sessionClient SessionClient,
	userService UserService,
	logger *zap.Logger,
) *TesterServer {
	server := &TesterServer{
		problemService: problemService,
		sessionClient:  sessionClient,
		userService:    userService,
		logger:         logger,
	}

	grpcServer := grpc.NewServer(
		grpc.UnaryInterceptor(server.ErrUnwrappingUnaryInterceptor()),
		grpc.StreamInterceptor(server.ErrUnwrappingStreamInterceptor()),
		grpc.UnaryInterceptor(server.AuthUnaryInterceptor()),
		grpc.StreamInterceptor(server.AuthStreamInterceptor()),
	)

	problemv1.RegisterProblemServiceServer(grpcServer, server)

	server.grpcServer = grpcServer

	return server
}

func (s *TesterServer) Start(lis net.Listener) error {
	return s.grpcServer.Serve(lis)
}

func (s *TesterServer) Stop() {
	s.grpcServer.GracefulStop()
}

func AsTimeP(t *timestamppb.Timestamp) *time.Time {
	if t == nil {
		return nil
	}
	tt := t.AsTime()
	return &tt
}

func AsTimestampP(t *time.Time) *timestamppb.Timestamp {
	if t == nil {
		return nil
	}
	return timestamppb.New(*t)
}
