// Copyright (c) 2021 XDPoSChain
// Copyright 2024 The go-ethereum Authors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package core

import (
	_ "embed"
	"encoding/json"
	"math/big"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/log"
	"github.com/ethereum/go-ethereum/params"
)

//go:embed xdc_genesis/mainnet.json
var xdcMainnetGenesisJSON []byte

//go:embed xdc_genesis/apothem.json
var xdcApothemGenesisJSON []byte

// XDC Network contract addresses (pre-deployed at genesis)
var (
	// XDCValidatorAddress is the masternode validator contract
	XDCValidatorAddress = common.HexToAddress("0x0000000000000000000000000000000000000088")
	// XDCBlockSignerAddress is the block signer contract
	XDCBlockSignerAddress = common.HexToAddress("0x0000000000000000000000000000000000000089")
	// XDCRandomizeAddress is the randomize contract
	XDCRandomizeAddress = common.HexToAddress("0x0000000000000000000000000000000000000090")
)

// DefaultXDCMainnetGenesisBlock returns the XDC mainnet genesis block.
// Uses the official genesis from xinfinorg/XDPoSChain to ensure exact hash match:
// 0x4a9d748bd78a8d0385b67788c2435dcdb914f98a96250b68863a1f8b7642d6b1
func DefaultXDCMainnetGenesisBlock() *Genesis {
	var genesis Genesis
	if err := json.Unmarshal(xdcMainnetGenesisJSON, &genesis); err != nil {
		log.Crit("Failed to unmarshal embedded mainnet genesis", "err", err)
	}
	return &genesis
}

// DefaultXDCApothemGenesisBlock returns the XDC Apothem testnet genesis block.
// Uses the official genesis from xinfinorg/XDPoSChain to ensure exact hash match:
// 0xbdea512b4f12ff1135ec92c00dc047ffb93890c2ea1aa0eefe9b013d80640075
func DefaultXDCApothemGenesisBlock() *Genesis {
	var genesis Genesis
	if err := json.Unmarshal(xdcApothemGenesisJSON, &genesis); err != nil {
		log.Crit("Failed to unmarshal embedded Apothem genesis", "err", err)
	}
	return &genesis
}

// xdcGenesisAlloc returns the genesis allocation for XDC mainnet
func xdcGenesisAlloc() GenesisAlloc {
	return GenesisAlloc{
		// Validator contract at 0x88
		XDCValidatorAddress: {
			Code:    hexutil.MustDecode("0x6080604052600436106100fb5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306a49fce811461010057806358e7525f1461016557806302aa9be21461019c5780632d15cc04146101c0578063302b6872146101e15780633477ee2e1461020a5780636dd7d8ea14610222578063a9a981a314610236578063ae6e43f51461025d578063b642facd1461027e578063d09f1ab41461029f578063d161c767146102b4578063d51b9e93146102c9578063d55b7dff146102fe578063ef18374a14610313575b600080fd5b34801561010c57600080fd5b50610115610328565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610151578181015183820152602001610139565b505050509050019250505060405180910390f35b34801561017157600080fd5b5061018660043573ffffffffffffffffffffffffffffffffffffffff1661038a565b60408051918252519081900360200190f35b3480156101a857600080fd5b506101be60043573ffffffffffffffffffffffffffffffffffffffff166024356103ac565b005b3480156101cc57600080fd5b5061011560043573ffffffffffffffffffffffffffffffffffffffff16610412565b3480156101ed57600080fd5b5061018673ffffffffffffffffffffffffffffffffffffffff6004358116906024351661049e565b34801561021657600080fd5b506101be60043561053f565b6101be60043573ffffffffffffffffffffffffffffffffffffffff16610613565b34801561024257600080fd5b5061024b6106f8565b60408051918252519081900360200190f35b34801561026957600080fd5b506101be60043573ffffffffffffffffffffffffffffffffffffffff166106fe565b34801561028a57600080fd5b5061011560043573ffffffffffffffffffffffffffffffffffffffff166108a1565b3480156102ab57600080fd5b5061024b61092d565b3480156102c057600080fd5b5061024b610933565b3480156102d557600080fd5b506102ea60043573ffffffffffffffffffffffffffffffffffffffff16610939565b604080519115158252519081900360200190f35b34801561030a57600080fd5b5061024b610965565b34801561031f57600080fd5b5061024b61096b565b6060600880548060200260200160405190810160405280929190818152602001828054801561038057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610355575b5050505050905090565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205490565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020526040902054811115610409576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601981526020017f4e6f7420656e6f7567682063616e64696461746520636170210000000000000081525060200191505060405180910390fd5b505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020908152604091829020805483518184028101840190945280845260609392830182828015610492575b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610457575b50505050509050919050565b600073ffffffffffffffffffffffffffffffffffffffff83166000908152600160205260409020600201600091505b81548110156105395782826001848154811015156104d857fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156105315782826001838154811015156104d857fe5b600101610457565b50919050565b600073ffffffffffffffffffffffffffffffffffffffff821633146105c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f596f7520617265206e6f7420746865206f776e6572212121000000000000000081525060200191505060405180910390fd5b506008805460001901909055565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040812060030154151561060c5760019150610610565b60009150610610565b50919050565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600160205260409020541633146106f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f596f7520617265206e6f7420746865206f776e6572212121000000000000000081525060200191505060405180910390fd5b5050565b60095481565b33600090815260016020526040902054151561079f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f596f7520617265206e6f7420612063616e64696461746500000000000000000081525060200191505060405180910390fd5b6001600160a060020a038116600090815260016020526040902060030154156108095760006001600160a060020a038216600090815260016020526040902060030154111561080957600019600160a060020a0382166000908152600160205260409020600301555b6000600160a060020a0382166000908152600160205260409020541461089d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f596f7520617265206e6f7420746865206f776e657200000000000000000000008152506020019150506040518091039052600090fd5b5050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020908152604091829020805483518184028101840190945280845260609392830182828015610921575b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116108ea575b50505050509050919050565b600d5481565b600e5481565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160205260409020600301546000191490565b600b5481565b600a548156"),
			Balance: big.NewInt(0),
		},
		// Block signer contract at 0x89
		XDCBlockSignerAddress: {
			Code:    hexutil.MustDecode("0x6080604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663e341eaa481146100585780632f54bf6e14610079578063f4145a83146100c0575b005b34801561006457600080fd5b506100566004356024356044356100e7565b34801561008557600080fd5b506100ac600435602435604435606435608435600160a060020a031660a435610155565b604080519115158252519081900360200190f35b3480156100cc57600080fd5b506100d56101a1565b60408051918252519081900360200190f35b600083815260016020818152604080842086855282528084208054808401825590855282852001805473ffffffffffffffffffffffffffffffffffffffff191633179055815187815290810186905280820185905290519192917f62855fa22e051687c32ac285857751f6d3f2c100c72f1c9c8e127a22b6612f76919081900360600190a1505050565b600082815260016020908152604080832084845290915281205460001982101561019957600082815260016020908152604080832084845290915290208054600019840190811061015257fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16836000191461018357506000610198565b506001610198565b506000610198565b5b9695505050505050565b600054815600a165627a7a723058209ed5ef882cb37ebc8d65d5e8cb2bcd57f8f2fe8e9f8f7c3cc93b69b57a3e1e780029"),
			Balance: big.NewInt(0),
		},
		// Randomize contract at 0x90
		XDCRandomizeAddress: {
			Code:    hexutil.MustDecode("0x6080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166334d38600811461005b578063d442d6cc14610094578063e11f5ba2146100a9575b600080fd5b34801561006757600080fd5b5061007c600160a060020a03600435166100be565b60408051918252519081900360200190f35b3480156100a057600080fd5b5061007c6100d9565b3480156100b557600080fd5b5061007c6100df565b600160a060020a031660009081526001602052604090205490565b60005481565b6000805481526002602052604090205490565b600082815260046020526040902054600160a060020a031633146101015761015e565b6000828152600260205260409020805490811061011a57fe5b9060005260206000209001548160008381526002602052604090208054929350839081101561013b57fe5b6000918252602082200155815461015390849061016b565b600191909101905550505b5050565b60008282111561016f57600080fd5b509003905600a165627a7a7230582068b0d8b3ad7ebd3a7b24a3f8f5f72f7aebae1c536cb48ed857b0c3918bfb71920029"),
			Balance: big.NewInt(0),
		},
	}
}

// xdcTestnetGenesisAlloc returns the genesis allocation for XDC Apothem testnet
func xdcTestnetGenesisAlloc() GenesisAlloc {
	// Same contract code as mainnet, but with testnet-specific allocations
	alloc := xdcGenesisAlloc()

	// Add faucet address with initial balance for testing
	faucetAddress := common.HexToAddress("0xF94729ed0a9A7ec13aB2c90f88C8D0dE98Fde59a")
	alloc[faucetAddress] = GenesisAccount{
		Balance: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1000000000)), // 1 billion XDC
	}

	return alloc
}

// IsXDCNetwork returns true if the chain config represents an XDC network
func IsXDCNetwork(config *params.ChainConfig) bool {
	return config != nil && config.XDPoS != nil
}
