// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Code generated by protoc-gen-go_gapic. DO NOT EDIT.

package migration

import (
	"context"
	"fmt"
	"math"
	"net/url"

	gax "github.com/googleapis/gax-go/v2"
	"google.golang.org/api/option"
	"google.golang.org/api/option/internaloption"
	gtransport "google.golang.org/api/transport/grpc"
	migrationpb "google.golang.org/genproto/googleapis/cloud/bigquery/migration/v2alpha"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

var newSqlTranslationClientHook clientHook

// SqlTranslationCallOptions contains the retry settings for each method of SqlTranslationClient.
type SqlTranslationCallOptions struct {
	TranslateQuery []gax.CallOption
}

func defaultSqlTranslationGRPCClientOptions() []option.ClientOption {
	return []option.ClientOption{
		internaloption.WithDefaultEndpoint("bigquerymigration.googleapis.com:443"),
		internaloption.WithDefaultMTLSEndpoint("bigquerymigration.mtls.googleapis.com:443"),
		internaloption.WithDefaultAudience("https://bigquerymigration.googleapis.com/"),
		internaloption.WithDefaultScopes(DefaultAuthScopes()...),
		internaloption.EnableJwtWithScope(),
		option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
		option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
			grpc.MaxCallRecvMsgSize(math.MaxInt32))),
	}
}

func defaultSqlTranslationCallOptions() *SqlTranslationCallOptions {
	return &SqlTranslationCallOptions{
		TranslateQuery: []gax.CallOption{},
	}
}

// internalSqlTranslationClient is an interface that defines the methods availaible from BigQuery Migration API.
type internalSqlTranslationClient interface {
	Close() error
	setGoogleClientInfo(...string)
	Connection() *grpc.ClientConn
	TranslateQuery(context.Context, *migrationpb.TranslateQueryRequest, ...gax.CallOption) (*migrationpb.TranslateQueryResponse, error)
}

// SqlTranslationClient is a client for interacting with BigQuery Migration API.
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
//
// Provides other SQL dialects to GoogleSQL translation operations.
type SqlTranslationClient struct {
	// The internal transport-dependent client.
	internalClient internalSqlTranslationClient

	// The call options for this service.
	CallOptions *SqlTranslationCallOptions
}

// Wrapper methods routed to the internal client.

// Close closes the connection to the API service. The user should invoke this when
// the client is no longer required.
func (c *SqlTranslationClient) Close() error {
	return c.internalClient.Close()
}

// setGoogleClientInfo sets the name and version of the application in
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *SqlTranslationClient) setGoogleClientInfo(keyval ...string) {
	c.internalClient.setGoogleClientInfo(keyval...)
}

// Connection returns a connection to the API service.
//
// Deprecated.
func (c *SqlTranslationClient) Connection() *grpc.ClientConn {
	return c.internalClient.Connection()
}

// TranslateQuery translates input queries from source dialects to GoogleSQL.
func (c *SqlTranslationClient) TranslateQuery(ctx context.Context, req *migrationpb.TranslateQueryRequest, opts ...gax.CallOption) (*migrationpb.TranslateQueryResponse, error) {
	return c.internalClient.TranslateQuery(ctx, req, opts...)
}

// sqlTranslationGRPCClient is a client for interacting with BigQuery Migration API over gRPC transport.
//
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
type sqlTranslationGRPCClient struct {
	// Connection pool of gRPC connections to the service.
	connPool gtransport.ConnPool

	// flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE
	disableDeadlines bool

	// Points back to the CallOptions field of the containing SqlTranslationClient
	CallOptions **SqlTranslationCallOptions

	// The gRPC API client.
	sqlTranslationClient migrationpb.SqlTranslationServiceClient

	// The x-goog-* metadata to be sent with each request.
	xGoogMetadata metadata.MD
}

// NewSqlTranslationClient creates a new sql translation service client based on gRPC.
// The returned client must be Closed when it is done being used to clean up its underlying connections.
//
// Provides other SQL dialects to GoogleSQL translation operations.
func NewSqlTranslationClient(ctx context.Context, opts ...option.ClientOption) (*SqlTranslationClient, error) {
	clientOpts := defaultSqlTranslationGRPCClientOptions()
	if newSqlTranslationClientHook != nil {
		hookOpts, err := newSqlTranslationClientHook(ctx, clientHookParams{})
		if err != nil {
			return nil, err
		}
		clientOpts = append(clientOpts, hookOpts...)
	}

	disableDeadlines, err := checkDisableDeadlines()
	if err != nil {
		return nil, err
	}

	connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
	if err != nil {
		return nil, err
	}
	client := SqlTranslationClient{CallOptions: defaultSqlTranslationCallOptions()}

	c := &sqlTranslationGRPCClient{
		connPool:             connPool,
		disableDeadlines:     disableDeadlines,
		sqlTranslationClient: migrationpb.NewSqlTranslationServiceClient(connPool),
		CallOptions:          &client.CallOptions,
	}
	c.setGoogleClientInfo()

	client.internalClient = c

	return &client, nil
}

// Connection returns a connection to the API service.
//
// Deprecated.
func (c *sqlTranslationGRPCClient) Connection() *grpc.ClientConn {
	return c.connPool.Conn()
}

// setGoogleClientInfo sets the name and version of the application in
// the `x-goog-api-client` header passed on each request. Intended for
// use by Google-written clients.
func (c *sqlTranslationGRPCClient) setGoogleClientInfo(keyval ...string) {
	kv := append([]string{"gl-go", versionGo()}, keyval...)
	kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
	c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
}

// Close closes the connection to the API service. The user should invoke this when
// the client is no longer required.
func (c *sqlTranslationGRPCClient) Close() error {
	return c.connPool.Close()
}

func (c *sqlTranslationGRPCClient) TranslateQuery(ctx context.Context, req *migrationpb.TranslateQueryRequest, opts ...gax.CallOption) (*migrationpb.TranslateQueryResponse, error) {
	md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
	ctx = insertMetadata(ctx, c.xGoogMetadata, md)
	opts = append((*c.CallOptions).TranslateQuery[0:len((*c.CallOptions).TranslateQuery):len((*c.CallOptions).TranslateQuery)], opts...)
	var resp *migrationpb.TranslateQueryResponse
	err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
		var err error
		resp, err = c.sqlTranslationClient.TranslateQuery(ctx, req, settings.GRPC...)
		return err
	}, opts...)
	if err != nil {
		return nil, err
	}
	return resp, nil
}
