package client

import (
	"context"
	"fmt"
	"log"

	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/discount"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
)

type DiscountClientDeps struct {
	Logger              *zap.Logger
	DiscountServiceHost string
}

type DiscountClient struct {
	logger              *zap.Logger
	discountServiceHost string
}

func NewDiscountClient(deps DiscountClientDeps) *DiscountClient {
	if deps.Logger == nil {
		log.Panicln("logger is nil on <NewDiscountClient>")
	}

	if validate.IsStringEmpty(deps.DiscountServiceHost) {
		log.Panicln("discount host is empty on <NewDiscountClient>")
	}

	return &DiscountClient{
		logger:              deps.Logger,
		discountServiceHost: deps.DiscountServiceHost,
	}
}

func (receiver *DiscountClient) Apply(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, errors.Error) {
	connection, err := grpc.Dial(receiver.discountServiceHost, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		receiver.logger.Error("failed to connect on <Apply> of <DiscountClient>", zap.Error(err), zap.String("discount host", receiver.discountServiceHost))
		return nil, errors.New(fmt.Errorf("failed connect to discount service: %w", err), errors.ErrInternalError)
	}
	defer func() {
		if closeErr := connection.Close(); closeErr != nil {
			receiver.logger.Error("failed to close connection on <Apply> of <DiscountClient>", zap.Error(closeErr))
		}
	}()

	client := discount.NewDiscountServiceClient(connection)

	response, err := client.ApplyDiscounts(ctx, request)
	if err != nil {
		receiver.logger.Error("failed to apply discounts on <Apply> of <DiscountClient>", zap.Error(err), zap.Any("request", request))
		return nil, errors.New(fmt.Errorf("failed to apply discounts: %w", err), errors.ErrInternalError)
	}

	return response, nil
}

func (receiver *DiscountClient) DeleteDiscount(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discount, errors.Error) {
	connection, err := grpc.Dial(receiver.discountServiceHost, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		receiver.logger.Error("failed to connect on <DeleteDiscount> of <DiscountClient>", zap.Error(err), zap.String("discount host", receiver.discountServiceHost))
		return nil, errors.New(fmt.Errorf("failed connect to discount service: %w", err), errors.ErrInternalError)
	}
	defer func() {
		if closeErr := connection.Close(); closeErr != nil {
			receiver.logger.Error("failed to close connection on <DeleteDiscount> of <DiscountClient>", zap.Error(closeErr))
		}
	}()

	client := discount.NewDiscountServiceClient(connection)

	response, err := client.DeleteDiscount(ctx, request)
	if err != nil {
		receiver.logger.Error("failed to apply discounts on <DeleteDiscount> of <DiscountClient>", zap.Error(err), zap.Any("request", request))
		return nil, errors.New(fmt.Errorf("failed to delete discount by id: %w", err), errors.ErrInternalError)
	}

	return response, nil
}
