/*
Copyright 2017 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

    http://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.
*/

package spanner

import (
	"errors"
	"fmt"

	proto3 "github.com/golang/protobuf/ptypes/struct"
	sppb "google.golang.org/genproto/googleapis/spanner/v1"
	"google.golang.org/grpc/codes"
)

// A Statement is a SQL query with named parameters.
//
// A parameter placeholder consists of '@' followed by the parameter name.
// Parameter names consist of any combination of letters, numbers, and
// underscores. Names may be entirely numeric (e.g., "WHERE m.id = @5").
// Parameters may appear anywhere that a literal value is expected. The same
// parameter name may be used more than once.  It is an error to execute a
// statement with unbound parameters. On the other hand, it is allowable to
// bind parameter names that are not used.
//
// See the documentation of the Row type for how Go types are mapped to Cloud
// Spanner types.
type Statement struct {
	SQL    string
	Params map[string]interface{}
}

// NewStatement returns a Statement with the given SQL and an empty Params map.
func NewStatement(sql string) Statement {
	return Statement{SQL: sql, Params: map[string]interface{}{}}
}

// errBindParam returns error for not being able to bind parameter to query request.
func errBindParam(k string, v interface{}, err error) error {
	if err == nil {
		return nil
	}
	se, ok := toSpannerError(err).(*Error)
	if !ok {
		return spannerErrorf(codes.InvalidArgument, "failed to bind query parameter(name: %q, value: %v), error = <%v>", k, v, err)
	}
	se.decorate(fmt.Sprintf("failed to bind query parameter(name: %q, value: %v)", k, v))
	return se
}

var (
	errNilParam = errors.New("use T(nil), not nil")
	errNoType   = errors.New("no type information")
)

// bindParams binds parameters in a Statement to a sppb.ExecuteSqlRequest or sppb.PartitionQueryRequest.
func (s *Statement) bindParams(i interface{}) error {
	params := &proto3.Struct{
		Fields: map[string]*proto3.Value{},
	}
	paramTypes := map[string]*sppb.Type{}
	for k, v := range s.Params {
		if v == nil {
			return errBindParam(k, v, errNilParam)
		}
		val, t, err := encodeValue(v)
		if err != nil {
			return errBindParam(k, v, err)
		}
		if t == nil { // should not happen, because of nil check above
			return errBindParam(k, v, errNoType)
		}
		params.Fields[k] = val
		paramTypes[k] = t
	}

	switch r := i.(type) {
	default:
		return fmt.Errorf("failed to bind query parameter, unexpected request type: %v", r)
	case *sppb.ExecuteSqlRequest:
		r.Params = params
		r.ParamTypes = paramTypes
	case *sppb.PartitionQueryRequest:
		r.Params = params
		r.ParamTypes = paramTypes
	}
	return nil
}
