// 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 firestore

import (
	"errors"
	"fmt"
	"time"

	"github.com/golang/protobuf/ptypes"
	pb "google.golang.org/genproto/googleapis/firestore/v1"
)

// A Precondition modifies a Firestore update or delete operation.
type Precondition interface {
	// Returns the corresponding Precondition proto.
	preconditionProto() (*pb.Precondition, error)
}

// Exists is a Precondition that checks for the existence of a resource before
// writing to it. If the check fails, the write does not occur.
var Exists Precondition

func init() {
	// Initialize here so godoc doesn't show the internal value.
	Exists = exists(true)
}

type exists bool

func (e exists) preconditionProto() (*pb.Precondition, error) {
	return &pb.Precondition{
		ConditionType: &pb.Precondition_Exists{bool(e)},
	}, nil
}

func (e exists) String() string {
	if e {
		return "Exists"
	}
	return "DoesNotExist"
}

// LastUpdateTime returns a Precondition that checks that a resource must exist and
// must have last been updated at the given time. If the check fails, the write
// does not occur.
func LastUpdateTime(t time.Time) Precondition { return lastUpdateTime(t) }

type lastUpdateTime time.Time

func (u lastUpdateTime) preconditionProto() (*pb.Precondition, error) {
	ts, err := ptypes.TimestampProto(time.Time(u))
	if err != nil {
		return nil, err
	}
	return &pb.Precondition{
		ConditionType: &pb.Precondition_UpdateTime{ts},
	}, nil
}

func (u lastUpdateTime) String() string { return fmt.Sprintf("LastUpdateTime(%s)", time.Time(u)) }

func processPreconditionsForDelete(preconds []Precondition) (*pb.Precondition, error) {
	// At most one option permitted.
	switch len(preconds) {
	case 0:
		return nil, nil
	case 1:
		return preconds[0].preconditionProto()
	default:
		return nil, fmt.Errorf("firestore: conflicting preconditions: %+v", preconds)
	}
}

func processPreconditionsForUpdate(preconds []Precondition) (*pb.Precondition, error) {
	// At most one option permitted, and it cannot be Exists.
	switch len(preconds) {
	case 0:
		// If the user doesn't provide any options, default to Exists(true).
		return exists(true).preconditionProto()
	case 1:
		if _, ok := preconds[0].(exists); ok {
			return nil, errors.New("cannot use Exists with Update")
		}
		return preconds[0].preconditionProto()
	default:
		return nil, fmt.Errorf("firestore: conflicting preconditions: %+v", preconds)
	}
}

func processPreconditionsForVerify(preconds []Precondition) (*pb.Precondition, error) {
	// At most one option permitted.
	switch len(preconds) {
	case 0:
		return nil, nil
	case 1:
		return preconds[0].preconditionProto()
	default:
		return nil, fmt.Errorf("firestore: conflicting preconditions: %+v", preconds)
	}
}

// A SetOption modifies a Firestore set operation.
type SetOption interface {
	fieldPaths() (fps []FieldPath, all bool, err error)
}

// MergeAll is a SetOption that causes all the field paths given in the data argument
// to Set to be overwritten. It is not supported for struct data.
var MergeAll SetOption = merge{all: true}

// Merge returns a SetOption that causes only the given field paths to be
// overwritten. Other fields on the existing document will be untouched. It is an
// error if a provided field path does not refer to a value in the data passed to
// Set.
func Merge(fps ...FieldPath) SetOption {
	for _, fp := range fps {
		if err := fp.validate(); err != nil {
			return merge{err: err}
		}
	}
	return merge{paths: fps}
}

type merge struct {
	all   bool
	paths []FieldPath
	err   error
}

func (m merge) String() string {
	if m.err != nil {
		return fmt.Sprintf("<Merge error: %v>", m.err)
	}
	if m.all {
		return "MergeAll"
	}
	return fmt.Sprintf("Merge(%+v)", m.paths)
}

func (m merge) fieldPaths() (fps []FieldPath, all bool, err error) {
	if m.err != nil {
		return nil, false, m.err
	}
	if err := checkNoDupOrPrefix(m.paths); err != nil {
		return nil, false, err
	}
	if m.all {
		return nil, true, nil
	}
	return m.paths, false, nil
}

func processSetOptions(opts []SetOption) (fps []FieldPath, all bool, err error) {
	switch len(opts) {
	case 0:
		return nil, false, nil
	case 1:
		return opts[0].fieldPaths()
	default:
		return nil, false, fmt.Errorf("conflicting options: %+v", opts)
	}
}
