// Copyright (c) 2015 The btcsuite developers
package wtxmgr_test

import (
	"fmt"

	"github.com/p9c/p9/pkg/chain/config/netparams"
	chainhash "github.com/p9c/p9/pkg/chain/hash"
	wtxmgr "github.com/p9c/p9/pkg/chain/tx/mgr"
	"github.com/p9c/p9/pkg/chain/wire"
	"github.com/p9c/p9/pkg/db/walletdb"
)

var (
	// Spends: bogus
	// Outputs: 10 DUO
	exampleTxRecordA *wtxmgr.TxRecord
	// Spends: A:0
	// Outputs: 5 DUO, 5 DUO
	exampleTxRecordB *wtxmgr.TxRecord
)

func init() {
	tx := spendOutput(&chainhash.Hash{}, 0, 10e8)
	rec, e := wtxmgr.NewTxRecordFromMsgTx(tx, timeNow())
	if e != nil  {
		panic(err)
	}
	exampleTxRecordA = rec
	tx = spendOutput(&exampleTxRecordA.Hash, 0, 5e8, 5e8)
	rec, e = wtxmgr.NewTxRecordFromMsgTx(tx, timeNow())
	if e != nil  {
		panic(err)
	}
	exampleTxRecordB = rec
}

var exampleBlock100 = makeBlockMeta(100)

// This example demonstrates reporting the Store balance given an unmined and mined transaction given 0, 1, and 6 block
// confirmations.
func ExampleStore_Balance() {
	s, db, teardown, e := testStore()
	defer teardown()
	if e != nil  {
				return
	}
	// Prints balances for 0 block confirmations, 1 confirmation, and 6
	// confirmations.
	printBalances := func(syncHeight int32) {
		dbtx, e := db.BeginReadTx()
		if e != nil  {
						return
		}
		defer func() {
			e := dbtx.Rollback()
			if e != nil  {
							}
		}()
		ns := dbtx.ReadBucket(namespaceKey)
		zeroConfBal, e := s.Balance(ns, 0, syncHeight)
		if e != nil  {
						return
		}
		oneConfBal, e := s.Balance(ns, 1, syncHeight)
		if e != nil  {
						return
		}
		sixConfBal, e := s.Balance(ns, 6, syncHeight)
		if e != nil  {
						return
		}
		fmt.Printf("%v, %v, %v\n", zeroConfBal, oneConfBal, sixConfBal)
	}
	// Insert a transaction which outputs 10 DUO unmined and mark the output
	// as a credit.
	e = walletdb.Update(db, func(tx walletdb.ReadWriteTx) (e error) {
		ns := tx.ReadWriteBucket(namespaceKey)
		e := s.InsertTx(ns, exampleTxRecordA, nil)
		if e != nil  {
			return err
		}
		return s.AddCredit(ns, exampleTxRecordA, nil, 0, false)
	})
	if e != nil  {
				return
	}
	printBalances(100)
	// Mine the transaction in block 100 and print balances again with a
	// sync height of 100 and 105 blocks.
	e = walletdb.Update(db, func(tx walletdb.ReadWriteTx) (e error) {
		ns := tx.ReadWriteBucket(namespaceKey)
		return s.InsertTx(ns, exampleTxRecordA, &exampleBlock100)
	})
	if e != nil  {
				return
	}
	printBalances(100)
	printBalances(105)
	// Output:
	// 10 DUO, 0 DUO, 0 DUO
	// 10 DUO, 10 DUO, 0 DUO
	// 10 DUO, 10 DUO, 10 DUO
}
func ExampleStore_Rollback() {
	s, db, teardown, e := testStore()
	defer teardown()
	if e != nil  {
				return
	}
	e = walletdb.Update(db, func(tx walletdb.ReadWriteTx) (e error) {
		ns := tx.ReadWriteBucket(namespaceKey)
		// Insert a transaction which outputs 10 DUO in a block at height 100.
		e := s.InsertTx(ns, exampleTxRecordA, &exampleBlock100)
		if e != nil  {
			return err
		}
		// Rollback everything from block 100 onwards.
		e = s.Rollback(ns, 100)
		if e != nil  {
			return err
		}
		// Assert that the transaction is now unmined.
		details, e := s.TxDetails(ns, &exampleTxRecordA.Hash)
		if e != nil  {
			return err
		}
		if details == nil {
			return fmt.Errorf("no details found")
		}
		fmt.Println(details.Block.Height)
		return nil
	})
	if e != nil  {
				return
	}
	// Output:
	// -1
}
func Example_basicUsage() {
	// Open the database.
	db, dbTeardown, e := testDB()
	defer dbTeardown()
	if e != nil  {
				return
	}
	// Open a read-write transaction to operate on the database.
	dbtx, e := db.BeginReadWriteTx()
	if e != nil  {
				return
	}
	defer func() {
		e := dbtx.Commit()
		if e != nil  {
					}
	}()
	// Create a bucket for the transaction store.
	b, e := dbtx.CreateTopLevelBucket([]byte("txstore"))
	if e != nil  {
				return
	}
	// Create and open the transaction store in the provided namespace.
	e = wtxmgr.Create(b)
	if e != nil  {
				return
	}
	s, e := wtxmgr.Open(b, &netparams.TestNet3Params)
	if e != nil  {
				return
	}
	// Insert an unmined transaction that outputs 10 DUO to a wallet address
	// at output 0.
	e = s.InsertTx(b, exampleTxRecordA, nil)
	if e != nil  {
				return
	}
	e = s.AddCredit(b, exampleTxRecordA, nil, 0, false)
	if e != nil  {
				return
	}
	// Insert a second transaction which spends the output, and creates two
	// outputs.  Mark the second one (5 DUO) as wallet change.
	e = s.InsertTx(b, exampleTxRecordB, nil)
	if e != nil  {
				return
	}
	e = s.AddCredit(b, exampleTxRecordB, nil, 1, true)
	if e != nil  {
				return
	}
	// Mine each transaction in a block at height 100.
	e = s.InsertTx(b, exampleTxRecordA, &exampleBlock100)
	if e != nil  {
				return
	}
	e = s.InsertTx(b, exampleTxRecordB, &exampleBlock100)
	if e != nil  {
				return
	}
	// Print the one confirmation balance.
	bal, e := s.Balance(b, 1, 100)
	if e != nil  {
				return
	}
	fmt.Println(bal)
	// Fetch unspent outputs.
	utxos, e := s.UnspentOutputs(b)
	if e != nil  {
			}
	expectedOutPoint := wire.OutPoint{Hash: exampleTxRecordB.Hash, Index: 1}
	for _, utxo := range utxos {
		fmt.Println(utxo.OutPoint == expectedOutPoint)
	}
	// Output:
	// 5 DUO
	// true
}
