package main

import (
	"bytes"
	"encoding/hex"
	"fmt"

	"github.com/muun/recovery/electrum"
	"github.com/muun/recovery/scanner"

	"github.com/btcsuite/btcd/chaincfg"

	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
	"github.com/muun/libwallet"
)

var (
	chainParams = chaincfg.MainNetParams
)

type Sweeper struct {
	UserKey      *libwallet.HDPrivateKey
	MuunKey      *libwallet.HDPrivateKey
	Birthday     int
	SweepAddress btcutil.Address
}

func (s *Sweeper) GetSweepTxAmountAndWeightInBytes(utxos []*scanner.Utxo) (outputAmount int64, weightInBytes int64, err error) {
	// we build a sweep tx with 0 fee with the only purpose of checking its signed size
	zeroFeeSweepTx, err := s.BuildSweepTx(utxos, 0)
	if err != nil {
		return 0, 0, err
	}

	outputAmount = zeroFeeSweepTx.TxOut[0].Value
	weightInBytes = int64(zeroFeeSweepTx.SerializeSize())

	return outputAmount, weightInBytes, nil
}

func (s *Sweeper) BuildSweepTx(utxos []*scanner.Utxo, fee int64) (*wire.MsgTx, error) {
	derivedMuunKey, err := s.MuunKey.DeriveTo("m/1'/1'")
	if err != nil {
		return nil, err
	}
	sweepTx, err := buildSweepTx(utxos, s.SweepAddress, fee)
	if err != nil {
		return nil, err
	}

	return buildSignedTx(utxos, sweepTx, s.UserKey, derivedMuunKey)
}

func (s *Sweeper) BroadcastTx(tx *wire.MsgTx) error {
	// Connect to an Electurm server using a fresh client and provider pair:
	sp := scanner.NewServerProvider() // TODO create servers module, for provider and pool
	client := electrum.NewClient()

	for !client.IsConnected() {
		client.Connect(sp.NextServer())
	}

	// Encode the transaction for broadcast:
	txBytes := new(bytes.Buffer)

	err := tx.BtcEncode(txBytes, wire.ProtocolVersion, wire.WitnessEncoding)
	if err != nil {
		return fmt.Errorf("error while encoding tx: %w", err)
	}

	txHex := hex.EncodeToString(txBytes.Bytes())

	// Do the thing!
	_, err = client.Broadcast(txHex)
	if err != nil {
		return fmt.Errorf("error while broadcasting: %w", err)
	}

	return nil
}
