// SPDX-License-Identifier: BUSL-1.1
//
// Copyright (C) 2025, Berachain Foundation. All rights reserved.
// Use of this software is governed by the Business Source License included
// in the LICENSE file of this repository and at www.mariadb.com/bsl11.
//
// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY
// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER
// VERSIONS OF THE LICENSED WORK.
//
// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF
// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF
// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE).
//
// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
// TITLE.

package types

import (
	"encoding/binary"

	"github.com/berachain/beacon-kit/primitives/common"
	"github.com/berachain/beacon-kit/primitives/constants"
	"github.com/berachain/beacon-kit/primitives/constraints"
	"github.com/karalabe/ssz"
)

var (
	_ ssz.StaticObject                    = (*SigningData)(nil)
	_ constraints.SSZMarshallableRootable = (*SigningData)(nil)
)

// SigningData as defined in the Ethereum 2.0 specification.
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#signingdata
type SigningData struct {
	// ObjectRoot is the hash tree root of the object being signed.
	ObjectRoot common.Root
	// Domain is the domain the object is being signed in.
	Domain common.Domain
}

/* -------------------------------------------------------------------------- */
/*                                     SSZ                                    */
/* -------------------------------------------------------------------------- */

// SizeSSZ returns the size of the SigningData object in SSZ encoding.
func (*SigningData) SizeSSZ(_ *ssz.Sizer) uint32 {
	//nolint:mnd // 32*2 = 64.
	return 64
}

// DefineSSZ defines the SSZ encoding for the SigningData object.
func (s *SigningData) DefineSSZ(codec *ssz.Codec) {
	ssz.DefineStaticBytes(codec, &s.ObjectRoot)
	ssz.DefineStaticBytes(codec, &s.Domain)
}

// HashTreeRoot computes the SSZ hash tree root of the SigningData object.
func (s *SigningData) HashTreeRoot() common.Root {
	return ssz.HashSequential(s)
}

// MarshalSSZTo marshals the SigningData object to SSZ format into the provided
// buffer.
func (s *SigningData) MarshalSSZTo(buf []byte) ([]byte, error) {
	return buf, ssz.EncodeToBytes(buf, s)
}

// MarshalSSZ marshals the SigningData object to SSZ format.
func (s *SigningData) MarshalSSZ() ([]byte, error) {
	buf := make([]byte, ssz.Size(s))
	return s.MarshalSSZTo(buf)
}

func (*SigningData) ValidateAfterDecodingSSZ() error { return nil }

// ComputeSigningRoot as defined in the Ethereum 2.0 specification.
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_signing_root
func ComputeSigningRoot(
	sszObject interface{ HashTreeRoot() common.Root },
	domain common.Domain,
) common.Root {
	return (&SigningData{
		ObjectRoot: sszObject.HashTreeRoot(),
		Domain:     domain,
	}).HashTreeRoot()
}

// ComputeSigningRootUInt64 computes the signing root of a uint64 value.
func ComputeSigningRootUInt64(
	value uint64,
	domain common.Domain,

) common.Root {
	bz := make([]byte, constants.RootLength)
	binary.LittleEndian.PutUint64(bz, value)
	return (&SigningData{
		ObjectRoot: common.Root(bz),
		Domain:     domain,
	}).HashTreeRoot()
}
