package main

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"math/big"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/ethereum/go-ethereum/common"
	types "github.com/ethereum/go-ethereum/core/types"
	ethclient "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	// Get the last block height
	var currentScanedBlock int64 = getLastTimeBlockNumber()
	addressArr := []string{"0x5b68ff12be7fd90284ebe2702050879d4d50061a"}
	// get operate signal
	makeSignal := make(chan os.Signal, 1)
	// monitor all signals
	signal.Notify(makeSignal, syscall.SIGINT)
	go start("https://galaxy.block.caduceus.foundation", addressArr, &currentScanedBlock)
	processSignal := <-makeSignal
	if processSignal != nil {
		fmt.Println(currentScanedBlock)
		stop(currentScanedBlock)
		fmt.Println("process end:", processSignal)
		os.Exit(3)
	}
}
func start(url string, addArr []string, currentScanedBlock *int64) {
	//Block until a signal comes in
	fmt.Println("monitor start")
	client, err := ethclient.Dial(url)
	if err != nil {
		log.Fatal(err)
	}
	// create ticker
	var ticker *time.Ticker = time.NewTicker(1 * time.Second)
	count := 10
	for {
		select {
		case <-ticker.C:
			{
				header, err := client.HeaderByNumber(context.Background(), nil)
				if err != nil {
					log.Fatalf(err.Error())
				}
				newBlockNum := header.Number.Int64()
				fmt.Println("newBlockNum:", newBlockNum)
				fmt.Println("currentScanedBlock:", &currentScanedBlock)
				for num := *currentScanedBlock; num < newBlockNum; num++ {
					if count == 0 {
						*currentScanedBlock = *currentScanedBlock + 100
						break
					}
					fmt.Println("current scan block number:", currentScanedBlock)
					for _, pendingVerifyAddress := range addArr {
						// Get tx with in a block
						if getBlockTxThroughAddress(client, big.NewInt(num), pendingVerifyAddress) {
							fmt.Println("verify success:", pendingVerifyAddress)
						} else {
							fmt.Println("verifing......", pendingVerifyAddress)
						}
					}
					count--
				}
			}
		}
	}
}
func getBlockTxThroughAddress(client *ethclient.Client, blockNumber *big.Int, verifyAddress string) bool {
	// Specify the block number and get the transactions in the block
	block, err := client.BlockByNumber(context.Background(), big.NewInt(blockNumber.Int64()))
	if err != nil {
		return false
	}
	// Get all tx in block
	for _, tx := range block.Transactions() {
		chainID, err := client.NetworkID(context.Background())
		if err != nil {
			log.Fatal(err)
		}
		msg, err := tx.AsMessage(types.NewEIP155Signer(chainID), big.NewInt(1000))
		if err == nil {
			fmt.Println("From:", msg.From().Hex())
		}
		// Get receipt status
		receipt, err := client.TransactionReceipt(context.Background(), tx.Hash())
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("receiptStatus:", receipt.Status)
		fmt.Println("toAddress:", tx.To().Hex(), "Value:", "Hash:", tx.Hash().Hex(), tx.Value().String())
		verifyAddressByte := common.HexToAddress(verifyAddress).Bytes()
		compareRes := bytes.Compare(tx.To().Bytes(), verifyAddressByte)
		if compareRes == 0 && receipt.Status == 1 {
			// storage tx
			storageTx(tx.Hash().Hex(), tx.Value().String(), msg.From().Hex(), tx.To().Hex())
			return true
		}
	}
	return false
}
func storageTx(tx string, amount string, from string, to string) {
	fmt.Println("storage hash:", tx, "amount:", amount, "from:", from, "to:", to)
}
func getLastTimeBlockNumber() (number int64) {
	number = 7048864
	return
}
func stop(blockNum int64) {
	// In Mysql storage end blockNum
	fmt.Println("Ticker stopped and storage blockNum:", blockNum)
}
