package bbolt_test

import (
	bolt "go.etcd.io/bbolt"
	"go.etcd.io/bbolt/internal/common"
)

// `dumpBucket` dumps all the data, including both key/value data
// and child buckets, from the source bucket into the target db file.
func dumpBucket(srcBucketName []byte, srcBucket *bolt.Bucket, dstFilename string) error {
	common.Assert(len(srcBucketName) != 0, "source bucket name can't be empty")
	common.Assert(srcBucket != nil, "the source bucket can't be nil")
	common.Assert(len(dstFilename) != 0, "the target file path can't be empty")

	dstDB, err := bolt.Open(dstFilename, 0600, nil)
	if err != nil {
		return err
	}
	defer dstDB.Close()

	return dstDB.Update(func(tx *bolt.Tx) error {
		dstBucket, err := tx.CreateBucket(srcBucketName)
		if err != nil {
			return err
		}
		return cloneBucket(srcBucket, dstBucket)
	})
}

func cloneBucket(src *bolt.Bucket, dst *bolt.Bucket) error {
	return src.ForEach(func(k, v []byte) error {
		if v == nil {
			srcChild := src.Bucket(k)
			dstChild, err := dst.CreateBucket(k)
			if err != nil {
				return err
			}
			if err = dstChild.SetSequence(srcChild.Sequence()); err != nil {
				return err
			}

			return cloneBucket(srcChild, dstChild)
		}

		return dst.Put(k, v)
	})
}