package arango_db

import (
	"context"
	"fmt"

	driver "github.com/arangodb/go-driver"
)

type Collection struct {
	db driver.Database
	driver.Collection
	ctx context.Context
}

// Добавление коллекции
func NewCollection(ctx context.Context, db driver.Database, name string) (*Collection, error) {
	collExists, errExists := db.CollectionExists(ctx, name)
	if errExists != nil {
		return nil, fmt.Errorf("AddCollection: Error checking the existence of the collection: %v", errExists)
	}

	// Предварительно проверим существование коллекции с таким же наименованием
	if collExists {
		col, err := db.Collection(ctx, name)
		if err != nil {
			return nil, fmt.Errorf("AddCollection: failed to open existing collection %v: %v", name, err)
		}

		return &Collection{
			db,
			col,
			ctx,
		}, nil
	}

	// Создадим коллекцию
	col, err := db.CreateCollection(ctx, name, nil)
	if err != nil {
		return nil, fmt.Errorf("AddCollection: failed to create collection %v: %v", name, err)
	}

	return &Collection{
		db,
		col,
		ctx,
	}, nil
}

// Добавление данных коллекции
func (col *Collection) AddData(data interface{}) error {
	_, errs, err := col.CreateDocuments(col.ctx, data)
	if err != nil {
		return fmt.Errorf("AddData: %v", err)
	} else if err := errs.FirstNonNil(); err != nil {
		return fmt.Errorf("AddData: first error: %v", err)
	}

	return nil
}

// Получение элементов коллекции
func (col *Collection) GetData(query string) (func() (interface{}, error), error) {
	cursor, err := col.db.Query(col.ctx, query, nil)
	if err != nil {
		return nil, fmt.Errorf("GetData: query '%v' failed: %v", query, err)
	}

	return func() (interface{}, error) {
		var doc interface{}

		/*metadata*/
		_, errRead := cursor.ReadDocument(col.ctx, &doc)
		if driver.IsNoMoreDocuments(errRead) {
			cursor.Close()

			return nil, fmt.Errorf("empty")
		} else if errRead != nil {
			return nil, fmt.Errorf("GetData: read document %v error %v", query, errRead)
		}

		return doc, nil
	}, nil
}

// Изменение коллекции
func (col *Collection) UpdateData(query string, patch interface{}) error {
	cursor, err := col.db.Query(col.ctx, query, nil)
	if err != nil {
		return fmt.Errorf("GetData: query '%v' failed: %v", query, err)
	}

	var doc map[string]interface{}

	/*metadata*/
	_, errRead := cursor.ReadDocument(col.ctx, &doc)
	if driver.IsNoMoreDocuments(errRead) {
		cursor.Close()
		return fmt.Errorf("empty")
	} else if errRead != nil {
		return fmt.Errorf("UpdateData: read document %v error %v", query, errRead)
	}

	//
	k, ok := doc["_key"]
	if !ok {
		return fmt.Errorf("UpdateData: key not found in %v", doc)
	}

	//
	_, errUpdate := col.UpdateDocument(col.ctx, k.(string), patch)
	if errUpdate != nil {
		return fmt.Errorf("UpdateData: update error %v", errUpdate)
	}

	return nil
}

/*
patch := map[string]interface{}{
    "name": "Frank",
}
*/