package client

import (
	"context"
	"fmt"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"io"
	"log"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
	codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
)

type CodewordClientDeps struct {
	Logger              *zap.Logger
	CodewordServiceHost string
}

type CodewordClient struct {
	logger              *zap.Logger
	codewordServiceHost string
}

func NewCodewordClient(deps CodewordClientDeps) *CodewordClient {
	if deps.Logger == nil {
		log.Panicln("logger is nil on <NewCodewordClient>")
	}

	if validate.IsStringEmpty(deps.CodewordServiceHost) {
		log.Panicln("codeword host is empty on <NewCodewordClient>")
	}

	return &CodewordClient{
		logger:              deps.Logger,
		codewordServiceHost: deps.CodewordServiceHost,
	}
}

func (receiver *CodewordClient) GetAllPromoActivations(ctx context.Context, req *codeword_rpc.Time) (map[string][]*codeword_rpc.PromoActivationResp_UserTime, errors.Error) {
	connection, err := grpc.Dial(receiver.codewordServiceHost, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		receiver.logger.Error("failed to connect on <GetAllPromoActivations> of <CodewordClient>", zap.Error(err), zap.String("codeword host", receiver.codewordServiceHost))
		return nil, errors.New(fmt.Errorf("failed connect to codeword service: %w", err), errors.ErrInternalError)
	}
	defer func() {
		if closeErr := connection.Close(); closeErr != nil {
			receiver.logger.Error("failed to close connection on <GetAllPromoActivations> of <CodewordClient>", zap.Error(closeErr))
		}
	}()

	client := codeword_rpc.NewPromoCodeServiceClient(connection)

	stream, err := client.GetAllPromoActivations(ctx, req)
	if err != nil {
		receiver.logger.Error("failed getting stats resp on <GetAllPromoActivations> of <DiscountClient>", zap.Error(err))
		return nil, errors.New(fmt.Errorf("failed getting stats resp from codeword: %w", err), errors.ErrInternalError)
	}

	response := make(map[string][]*codeword_rpc.PromoActivationResp_UserTime)

	for {
		activations, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, errors.New(fmt.Errorf("failed to receive response stream in codeword rpc client: %w", err), errors.ErrInternalError)
		}

		if activations == nil {
			continue
		}

		response[activations.ID] = append(response[activations.ID], activations.Users...)

	}

	return response, nil
}
