package main

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"time"

	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
	"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
	"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
)

const (
	configFile = "config/config.yaml"
	// org MSPID
	mspId = "org-251005746.fabric-5x6wdaow3q"
	// username
	username = "test"
	// channelId
	channelId = "channel-9xjcb2"
	// contract name
	contractName = "gotest"
)

func main() {
	gw, err := buildGateway()
	if err != nil {
		panic(err)
	}
	defer gw.Close()
	network, err := gw.GetNetwork(channelId)
	if err != nil {
		panic(err)
	}
	contract := network.GetContract(contractName)

	// registering Listener Events
	reg, notifier, err := network.RegisterBlockEvent()
	if err != nil {
		fmt.Printf("Failed to register block event: %s\n", err)
		return
	}
	defer network.Unregister(reg)

	// using gateway to call contract
	txId, _, err := contract.SubmitTransactionWithTxId("Set", "A", "100")
	if err != nil {
		fmt.Printf("SubmitTransaction error, %v\n", err)
		return
	}
	fmt.Printf("submit transaction: %s\n", txId)

	
	var bEvent *fab.BlockEvent
	select {
	case bEvent = <-notifier:
		fmt.Printf("Received block event: %#v\n", bEvent)
	case <-time.After(time.Second * 20):
		fmt.Printf("Did NOT receive block event\n")
	}
	if bEvent != nil {
		fmt.Printf("%v\n", bEvent.Block)
	}

	// use gateway to query contracts
	b, err := contract.EvaluateTransaction("Get", "A")
	if err != nil {
		fmt.Printf("EvaluateTransaction error, %v\n", err)
		return
	}
	fmt.Printf("query b: %s\n", string(b))
	return

}

// buildGateway init gateway
func buildGateway() (*gateway.Gateway, error) {
	wallet, err := gateway.NewFileSystemWallet("wallet")
	if err != nil {
		return nil, fmt.Errorf("NewFileSystemWallet error, %v", err)
	}
	if wallet.Exists(username) {
		if err := wallet.Remove(username); err != nil {
			return nil, fmt.Errorf("Remove error, %v", err)
		}
	}
	err = populateWallet(wallet, mspId, username)
	if err != nil {
		return nil, fmt.Errorf("populateWallet error, %v", err)
	}
	gw, err := gateway.Connect(
		gateway.WithConfig(config.FromFile(configFile)),
		gateway.WithIdentity(wallet, username),
	)
	if err != nil {
		return nil, fmt.Errorf("Connect error, %v", err)
	}
	return gw, nil
}

// populateWallet init wallet
func populateWallet(wallet *gateway.Wallet, mspId, username string) error {
	credPath := filepath.Join("config", username)
	certPath := filepath.Join(credPath, "user_sign.crt")
	cert, err := ioutil.ReadFile(certPath)
	if err != nil {
		return fmt.Errorf("ReadFile error, %v", err)
	}

	var key []byte
	keyPath := filepath.Join(credPath, "user_ecc_sign.key")
	key, err = ioutil.ReadFile(keyPath)
	if err != nil {
		keyPath := filepath.Join(credPath, "user_sm2_sign.key")
		key, err = ioutil.ReadFile(keyPath)
		if err != nil {
			return fmt.Errorf("ReadFile error, %v", err)
		}
	}

	identity := gateway.NewX509Identity(mspId, string(cert), string(key))
	return wallet.Put(username, identity)
}
