// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fake provides a fake implementation of a Datastore client
// to use in testing.
package fake

import (
	"bytes"
	"context"
	"encoding/gob"
	"log"
	"reflect"
	"sync"

	"cloud.google.com/go/datastore"
	"github.com/googleapis/google-cloud-go-testing/datastore/dsiface"
)

// Client is a fake implementation of dsiface.Client to use in
// testing.
type Client struct {
	dsiface.Client

	m  sync.Mutex
	db map[string]map[string][]byte
}

var _ dsiface.Client = &Client{}

// Close is unimplemented and panics.
func (f *Client) Close() error {
	panic("unimplemented")
}

// AllocateIDs is unimplemented and panics.
func (f *Client) AllocateIDs(context.Context, []*datastore.Key) ([]*datastore.Key, error) {
	panic("unimplemented")
}

// Count is unimplemented and panics.
func (f *Client) Count(context.Context, *datastore.Query) (n int, err error) {
	panic("unimplemented")
}

// Delete is unimplemented and panics.
func (f *Client) Delete(context.Context, *datastore.Key) error {
	panic("unimplemented")
}

// DeleteMulti is unimplemented and panics.
func (f *Client) DeleteMulti(context.Context, []*datastore.Key) (err error) {
	panic("unimplemented")
}

// Get loads the entity stored for key into dst, which must be a
// struct pointer.
func (f *Client) Get(_ context.Context, key *datastore.Key, dst interface{}) (err error) {
	f.m.Lock()
	defer f.m.Unlock()
	if f == nil {
		return datastore.ErrNoSuchEntity
	}
	// get catches nil interfaces; we need to catch nil ptr here
	if dst == nil {
		return datastore.ErrInvalidEntityType
	}
	kdb := f.db[key.Kind]
	if kdb == nil {
		return datastore.ErrNoSuchEntity
	}
	rv := reflect.ValueOf(dst)
	if rv.Kind() != reflect.Ptr {
		return datastore.ErrInvalidEntityType
	}
	v := kdb[key.Encode()]
	if v == nil {
		return datastore.ErrNoSuchEntity
	}
	d := gob.NewDecoder(bytes.NewReader(v))
	return d.Decode(dst)
}

// GetAll runs the provided query in the given context and returns all
// keys that match that query, as well as appending the values to dst.
//
// GetAll currently only supports a query of all entities of a given
// Kind, and a dst of a slice of pointers to structs.
func (f *Client) GetAll(_ context.Context, q *datastore.Query, dst interface{}) (keys []*datastore.Key, err error) {
	f.m.Lock()
	defer f.m.Unlock()
	fv := reflect.ValueOf(q).Elem().FieldByName("kind")
	kdb := f.db[fv.String()]
	if kdb == nil {
		return
	}
	s := reflect.ValueOf(dst).Elem()
	for k, v := range kdb {
		dk, err := datastore.DecodeKey(k)
		if err != nil {
			log.Printf("f.GetAll() failed to decode key %q: %v", k, err)
			continue
		}
		keys = append(keys, dk)
		// This value is expected to represent a slice of pointers to structs.
		ev := reflect.New(s.Type().Elem().Elem())
		d := gob.NewDecoder(bytes.NewReader(v))
		if err := d.DecodeValue(ev); err != nil {
			return nil, err
		}
		s.Set(reflect.Append(s, ev))
	}
	return
}

// GetMulti is unimplemented and panics.
func (f *Client) GetMulti(context.Context, []*datastore.Key, interface{}) (err error) {
	panic("unimplemented")
}

// Mutate is unimplemented and panics.
func (f *Client) Mutate(context.Context, ...*datastore.Mutation) (ret []*datastore.Key, err error) {
	panic("unimplemented")
}

// NewTransaction is unimplemented and panics.
func (f *Client) NewTransaction(context.Context, ...datastore.TransactionOption) (t dsiface.Transaction, err error) {
	panic("unimplemented")
}

// Put saves the entity src into the datastore with the given key. src
// must be a struct pointer.
func (f *Client) Put(_ context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
	f.m.Lock()
	defer f.m.Unlock()
	if f.db == nil {
		f.db = make(map[string]map[string][]byte)
	}
	kdb := f.db[key.Kind]
	if kdb == nil {
		f.db[key.Kind] = make(map[string][]byte)
		kdb = f.db[key.Kind]
	}
	dst := bytes.Buffer{}
	e := gob.NewEncoder(&dst)
	if err := e.Encode(src); err != nil {
		return nil, err
	}
	kdb[key.Encode()] = dst.Bytes()
	return key, nil
}

// PutMulti is unimplemented and panics.
func (f *Client) PutMulti(context.Context, []*datastore.Key, interface{}) (ret []*datastore.Key, err error) {
	panic("unimplemented")
}

// Run is unimplemented and panics.
func (f *Client) Run(context.Context, *datastore.Query) dsiface.Iterator {
	panic("unimplemented")
}

// RunInTransaction is unimplemented and panics.
func (f *Client) RunInTransaction(context.Context, func(tx dsiface.Transaction) error, ...datastore.TransactionOption) (cmt dsiface.Commit, err error) {
	panic("unimplemented")
}
