package boltdb

import (
	"fmt"

	"fiatjaf.com/nostr"
	"fiatjaf.com/nostr/eventstore"
	"fiatjaf.com/nostr/eventstore/codec/betterbinary"
	"go.etcd.io/bbolt"
)

func (b *BoltBackend) SaveEvent(evt nostr.Event) error {
	return b.DB.Update(func(txn *bbolt.Tx) error {
		if b.EnableHLLCacheFor != nil {
			// modify hyperloglog caches relative to this
			useCache, skipSaving := b.EnableHLLCacheFor(evt.Kind)

			if useCache {
				err := b.updateHyperLogLogCachedValues(txn, evt)
				if err != nil {
					return fmt.Errorf("failed to update hll cache: %w", err)
				}
				if skipSaving {
					return nil
				}
			}
		}

		rawBucket := txn.Bucket(rawEventStore)

		// check if we already have this id
		bin := rawBucket.Get(evt.ID[16:24])
		if bin != nil {
			// we should get nil, otherwise we already have it so end here
			return eventstore.ErrDupEvent
		}

		return b.save(txn, evt)
	})
}

func (b *BoltBackend) save(txn *bbolt.Tx, evt nostr.Event) error {
	rawBucket := txn.Bucket(rawEventStore)

	// encode to binary form so we'll save it
	bin := make([]byte, betterbinary.Measure(evt))
	if err := betterbinary.Marshal(evt, bin); err != nil {
		return err
	}

	// raw event store
	if err := rawBucket.Put(evt.ID[16:24], bin); err != nil {
		return err
	}

	// put indexes
	for k := range b.getIndexKeysForEvent(evt) {
		err := txn.Bucket(k.bucket).Put(k.fullkey, nil)
		if err != nil {
			return err
		}
	}

	return nil
}
