package api

import (
	"context"

	"github.com/vapor/account"
	"github.com/vapor/blockchain/pseudohsm"
	"github.com/vapor/crypto/ed25519/chainkd"
	"github.com/vapor/errors"
)

// POST /wallet error
func (a *API) walletError() Response {
	return NewErrorResponse(errors.New("wallet not found, please check that the wallet is open"))
}

// WalletImage hold the ziped wallet data
type WalletImage struct {
	AccountImage *account.Image      `json:"account_image"`
	KeyImages    *pseudohsm.KeyImage `json:"key_images"`
}

func (a *API) restoreWalletImage(ctx context.Context, image WalletImage) Response {
	if err := a.wallet.Hsm.Restore(image.KeyImages); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore key images"))
	}
	if err := a.wallet.AccountMgr.Restore(image.AccountImage); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore account image"))
	}

	var allAccounts []*account.Account
	for _, acctImage := range image.AccountImage.Slice {
		allAccounts = append(allAccounts, acctImage.Account)
	}

	if err := a.wallet.RecoveryMgr.AddrResurrect(allAccounts); err != nil {
		return NewErrorResponse(err)
	}

	a.wallet.RescanBlocks()
	return NewSuccessResponse(nil)
}

func (a *API) backupWalletImage() Response {
	keyImages, err := a.wallet.Hsm.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup key images"))
	}
	accountImage, err := a.wallet.AccountMgr.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup account image"))
	}

	image := &WalletImage{
		KeyImages:    keyImages,
		AccountImage: accountImage,
	}
	return NewSuccessResponse(image)
}

func (a *API) rescanWallet() Response {
	allAccounts, err := a.wallet.AccountMgr.ListAccounts("")
	if err != nil {
		return NewErrorResponse(err)
	}

	if err := a.wallet.RecoveryMgr.AddrResurrect(allAccounts); err != nil {
		return NewErrorResponse(err)
	}

	a.wallet.RescanBlocks()
	return NewSuccessResponse(nil)
}

// WalletInfo return wallet information
type WalletInfo struct {
	BestBlockHeight uint64 `json:"best_block_height"`
	WalletHeight    uint64 `json:"wallet_height"`
}

func (a *API) getWalletInfo() Response {
	bestBlockHeight := a.chain.BestBlockHeight()
	walletStatus := a.wallet.GetWalletStatusInfo()

	return NewSuccessResponse(&WalletInfo{
		BestBlockHeight: bestBlockHeight,
		WalletHeight:    walletStatus.WorkHeight,
	})
}

func (a *API) recoveryFromRootXPubs(ctx context.Context, in struct {
	XPubs []chainkd.XPub `json:"xpubs"`
}) Response {
	if err := a.wallet.RecoveryMgr.AcctResurrect(in.XPubs); err != nil {
		return NewErrorResponse(err)
	}

	a.wallet.RescanBlocks()
	return NewSuccessResponse(nil)
}
